import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.CompletionStage;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.ToolTipManager;
+import javax.swing.border.EmptyBorder;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
import jalview.ws.params.ArgumentI;
import jalview.ws.params.ParamDatastoreI;
import jalview.ws.params.WsParamSetI;
+import jalview.ws2.actions.BaseTask;
+import jalview.ws2.actions.PollingTaskExecutor;
import jalview.ws2.actions.alignment.AlignmentAction;
+import jalview.ws2.actions.alignment.AlignmentResult;
+import jalview.ws2.actions.annotation.AlignCalcWorkerAdapter;
+import jalview.ws2.actions.annotation.AnnotationAction;
import jalview.ws2.actions.api.ActionI;
import jalview.ws2.actions.api.TaskI;
import jalview.ws2.api.Credentials;
{
if (oneshot != null)
categoryMenu.addSeparator();
- // addInteractiveEntries(interactive, categoryMenu);
+ addInteractiveEntries(interactive, categoryMenu);
}
menu.add(categoryMenu);
}
private void addOneshotEntries(List<WebService<?>> services, JMenu menu)
{
- services.sort(Comparator
- .<WebService<?>, String> comparing(s -> s.getUrl().toString())
- .thenComparing(WebService::getName));
+ // Workaround. Comparator methods not working in j2s
+ services.sort((ws1, ws2) -> {
+ var res = ws1.getUrl().toString().compareTo(ws2.getUrl().toString());
+ if (res == 0)
+ res = ws1.getName().compareTo(ws2.getName());
+ return res;
+ });
URL lastHost = null;
for (WebService<?> service : services)
{
{
actionsByCategory
.computeIfAbsent(
- Objects.requireNonNullElse(action.getSubcategory(), ""),
+ action.getSubcategory() != null ? action.getSubcategory() : "",
k -> new ArrayList<>())
.add(action);
}
- actionsByCategory.forEach((k, v) -> {
+ for (var entry : actionsByCategory.entrySet())
+ {
+ var category = entry.getKey();
+ var actions = entry.getValue();
// create submenu named {subcategory} with {service} or use root menu
- var atMenu = k.isEmpty() ? menu : new JMenu(String.format("%s with %s", k, service.getName()));
+ var atMenu = category.isEmpty() ? menu : new JMenu(String.format("%s with %s", category, service.getName()));
if (atMenu != menu)
menu.add(atMenu); // add only if submenu
// sort actions by name pulling nulls to the front
- v.sort(Comparator.comparing(
+ actions.sort(Comparator.comparing(
ActionI::getName, Comparator.nullsFirst(Comparator.naturalOrder())));
- for (ActionI<?> action : v)
+ for (int i = 0; i < actions.size(); i++)
{
- addEntriesForAction(action, atMenu, atMenu == menu);
+ addEntriesForAction(actions.get(i), atMenu, atMenu == menu);
}
- });
+ }
}
}
{
String text = itemName;
if (datastore.hasParameters() || datastore.hasPresets())
- text += "with defaults";
+ text += " with defaults";
JMenuItem item = new JMenuItem(text);
item.addActionListener(e -> {
runAction(action, frame.getCurrentView(), Collections.emptyList(),
}
}
- private TaskI<?> runAction(ActionI<?> action, AlignmentViewport viewport,
+ private void addInteractiveEntries(List<WebService<?>> services, JMenu menu)
+ {
+ Map<String, List<WebService<?>>> byServiceName = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ for (var service : services)
+ {
+ byServiceName.computeIfAbsent(service.getName(), k -> new ArrayList<>())
+ .add(service);
+ }
+ for (var entry : byServiceName.entrySet())
+ {
+ var group = new InteractiveServiceEntryGroup(entry.getKey(), entry.getValue());
+ group.appendTo(menu);
+ }
+ }
+
+ private class InteractiveServiceEntryGroup
+ {
+ JLabel serviceLabel;
+
+ JMenuItem urlItem = new JMenuItem();
+
+ JCheckBoxMenuItem serviceItem = new JCheckBoxMenuItem();
+
+ JMenuItem editParamsItem = new JMenuItem("Edit parameters...");
+
+ JMenu presetsMenu = new JMenu("Change preset");
+
+ JMenu alternativesMenu = new JMenu("Choose action");
+ {
+ urlItem.setForeground(Color.BLUE);
+ urlItem.setVisible(false);
+ serviceItem.setVisible(false);
+ editParamsItem.setVisible(false);
+ presetsMenu.setVisible(false);
+ }
+
+ InteractiveServiceEntryGroup(String name, List<WebService<?>> services)
+ {
+ serviceLabel = new JLabel(name);
+ serviceLabel.setBorder(new EmptyBorder(0, 6, 0, 6));
+ buildAlternativesMenu(services);
+ }
+
+ private void buildAlternativesMenu(List<WebService<?>> services)
+ {
+ var menu = alternativesMenu;
+ services.sort((ws1, ws2) -> {
+ var res = ws1.getUrl().toString().compareTo(ws2.getUrl().toString());
+ if (res == 0)
+ res = ws1.getName().compareTo(ws2.getName());
+ return res;
+ });
+ URL lastHost = null;
+ for (var service : services)
+ {
+ // Adding url "separator" before each group
+ URL host = service.getUrl();
+ if (!host.equals(lastHost))
+ {
+ if (lastHost != null)
+ menu.addSeparator();
+ var item = new JMenuItem(host.toString());
+ item.setForeground(Color.BLUE);
+ item.addActionListener(e -> Desktop.showUrl(host.toString()));
+ menu.add(item);
+ lastHost = host;
+ }
+ menu.addSeparator();
+ var actionsByCategory = new TreeMap<String, List<ActionI<?>>>();
+ for (ActionI<?> action : service.getActions())
+ {
+ actionsByCategory
+ .computeIfAbsent(
+ action.getSubcategory() != null ? action.getSubcategory() : "",
+ k -> new ArrayList<>())
+ .add(action);
+ }
+ actionsByCategory.forEach((key, actions) -> {
+ var atMenu = key.isEmpty() ? menu : new JMenu(key + " with " + service.getName());
+ boolean topLevel = atMenu == menu;
+ if (!topLevel)
+ menu.add(atMenu);
+ actions.sort(Comparator.comparing(
+ a -> a.getName(),
+ Comparator.nullsFirst(Comparator.naturalOrder())));
+ for (ActionI<?> action : actions)
+ {
+ var item = new JMenuItem(action.getFullName());
+ item.addActionListener(e -> setAlternative(action));
+ atMenu.add(item);
+ }
+ });
+ }
+ }
+
+ private void setAlternative(ActionI<?> action)
+ {
+ final var arguments = new ArrayList<ArgumentI>();
+ final WsParamSetI[] lastPreset = { null };
+
+ // update selected url menu item
+ String url = action.getWebService().getUrl().toString();
+ urlItem.setText(url);
+ urlItem.setVisible(true);
+ for (var l : urlItem.getActionListeners())
+ urlItem.removeActionListener(l);
+ urlItem.addActionListener(e -> Desktop.showUrl(url));
+
+ // update selected service menu item
+ serviceItem.setText(action.getFullName());
+ serviceItem.setVisible(true);
+ for (var l : serviceItem.getActionListeners())
+ serviceItem.removeActionListener(l);
+ WebService<?> service = action.getWebService();
+ serviceItem.addActionListener(e -> {
+ runAction(action, frame.getCurrentView(), arguments,
+ Credentials.empty());
+ });
+ serviceItem.setSelected(true);
+
+ // update edit parameters menu item
+ var datastore = service.getParamDatastore();
+ editParamsItem.setVisible(datastore.hasParameters());
+ for (var l : editParamsItem.getActionListeners())
+ editParamsItem.removeActionListener(l);
+ if (datastore.hasParameters())
+ {
+ editParamsItem.addActionListener(e -> {
+ openEditParamsDialog(service.getParamDatastore(), lastPreset[0], arguments)
+ .thenAccept(args -> {
+ if (args != null)
+ {
+ lastPreset[0] = null;
+ arguments.clear();
+ arguments.addAll(args);
+ runAction(action, frame.getCurrentView(),
+ arguments, Credentials.empty());
+ }
+ });
+ });
+ }
+
+ // update presets menu
+ presetsMenu.removeAll();
+ presetsMenu.setEnabled(datastore.hasPresets());
+ if (datastore.hasPresets())
+ {
+ for (WsParamSetI preset : datastore.getPresets())
+ {
+ var item = new JMenuItem(preset.getName());
+ item.addActionListener(e -> {
+ lastPreset[0] = preset;
+ runAction(action, frame.getCurrentView(),
+ preset.getArguments(), Credentials.empty());
+ });
+ presetsMenu.add(item);
+ }
+ }
+
+ runAction(action, frame.getCurrentView(), arguments,
+ Credentials.empty());
+ }
+
+ void appendTo(JMenu menu)
+ {
+ menu.add(serviceLabel);
+ menu.add(urlItem);
+ menu.add(serviceItem);
+ menu.add(editParamsItem);
+ menu.add(presetsMenu);
+ menu.add(alternativesMenu);
+ }
+ }
+
+
+ private void runAction(ActionI<?> action, AlignmentViewport viewport,
List<ArgumentI> args, Credentials credentials)
{
// casting and instance checks can be avoided with some effort,
// TODO: test if selection contains enough sequences
var _action = (AlignmentAction) action;
var handler = new AlignmentServiceGuiHandler(_action, frame);
- return _action.perform(viewport, args, credentials, handler);
+ BaseTask<?, AlignmentResult> task = _action.createTask(viewport, args, credentials);
+ var executor = PollingTaskExecutor.fromPool(viewport.getServiceExecutor());
+ task.addTaskEventListener(handler);
+ var future = executor.submit(task);
+ task.setCancelAction(() -> { future.cancel(true); });
+ return;
+ }
+ if (action instanceof AnnotationAction)
+ {
+ var calcManager = viewport.getCalcManager();
+
+ var _action = (AnnotationAction) action;
+ var worker = new AlignCalcWorkerAdapter(viewport, frame.alignPanel,
+ _action, args, credentials);
+ var handler = new AnnotationServiceGuiHandler(_action, frame);
+ worker.addTaskEventListener(handler);
+ for (var w : calcManager.getWorkers())
+ {
+ if (worker.getCalcName() != null && worker.getCalcName().equals(w.getCalcName()))
+ {
+ calcManager.cancelWorker(w);
+ calcManager.removeWorker(w);
+ }
+ }
+ if (action.getWebService().isInteractive())
+ calcManager.registerWorker(worker);
+ else
+ calcManager.startWorker(worker);
+ return;
}
throw new IllegalArgumentException(
String.format("Illegal action type %s", action.getClass().getName()));
{
final WsJobParameters jobParams;
if (preset == null && arguments != null && arguments.size() > 0)
- jobParams = new WsJobParameters(paramStore, preset, arguments);
+ jobParams = new WsJobParameters(paramStore, null, arguments);
else
jobParams = new WsJobParameters(paramStore, preset, null);
if (preset != null)