JAL-3878 Separate gui elements from operations.
[jalview.git] / src / jalview / ws2 / gui / AnnotationMenuBuilder.java
diff --git a/src/jalview/ws2/gui/AnnotationMenuBuilder.java b/src/jalview/ws2/gui/AnnotationMenuBuilder.java
new file mode 100644 (file)
index 0000000..a1b2316
--- /dev/null
@@ -0,0 +1,190 @@
+package jalview.ws2.gui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+
+import jalview.api.AlignCalcManagerI2;
+import jalview.api.AlignmentViewPanel;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.WsJobParameters;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws2.MenuEntryProviderI;
+import jalview.ws2.PollingTaskExecutor;
+import jalview.ws2.operations.AnnotationOperation;
+import jalview.ws2.operations.AnnotationServiceWorker;
+
+public class AnnotationMenuBuilder implements MenuEntryProviderI
+{
+  final AnnotationOperation operation;
+  
+  public AnnotationMenuBuilder(AnnotationOperation operation)
+  {
+    this.operation = operation;
+  }
+
+  @Override
+  public void buildMenu(JMenu parent, AlignFrame frame)
+  {
+    if (operation.isInteractive())
+      buildInteractiveMenu(parent, frame);
+    else
+      buildClassicMenu(parent, frame);
+  }
+
+  protected void buildClassicMenu(JMenu parent, AlignFrame frame)
+  {
+    final var calcName = operation.getName();
+    PollingTaskExecutor wsExecutor = frame.getViewport().getWSExecutor();
+    final var calcManager = frame.getViewport().getCalcManager();
+    {
+      var item = new JMenuItem(MessageManager.formatMessage(
+          "label.calcname_with_default_settings", calcName));
+      item.addActionListener((event) -> {
+        var worker = createWorker(Collections.emptyList(), frame, calcManager);
+        calcManager.startWorker(worker);
+      });
+      parent.add(item);
+    }
+    if (operation.hasParameters())
+    {
+      var item = new JMenuItem(
+          MessageManager.getString("label.edit_settings_and_run"));
+      item.setToolTipText(MessageManager.getString(
+          "label.view_and_change_parameters_before_running_calculation"));
+      item.addActionListener((event) -> {
+        openEditParamsDialog(operation.getParamStore(), null, null)
+            .thenAcceptAsync((arguments) -> {
+              if (arguments != null)
+              {
+                var worker = createWorker(arguments, frame, calcManager);
+                calcManager.startWorker(worker);
+              }
+            });
+      });
+      parent.add(item);
+    }
+  }
+
+  protected void buildInteractiveMenu(JMenu parent, AlignFrame frame)
+  {
+    final var calcName = operation.getName();
+    final var calcManager = frame.getViewport().getCalcManager();
+    final var arguments = new ArrayList<ArgumentI>();
+    final JCheckBoxMenuItem runItem;
+    {
+      // TODO use MessageManager and set tool tip text
+      runItem = new JCheckBoxMenuItem(
+          String.format("%s calculations", calcName));
+      runItem.addActionListener((event) -> {
+        calcManager.removeWorkersForName(calcName);
+        var worker = createWorker(arguments, frame, calcManager);
+        calcManager.registerWorker(worker);
+      });
+      parent.add(runItem);
+    }
+    JMenuItem _editItem = null;
+    if (operation.hasParameters())
+    {
+      // TODO use MessageManager and set tool tip text
+      _editItem = new JMenuItem(
+          String.format("Edit %s settings", calcName));
+      _editItem.addActionListener((event) -> {
+        openEditParamsDialog(operation.getParamStore(), null, null)
+            .thenAcceptAsync((args) -> {
+              if (arguments != null)
+              {
+                arguments.clear();
+                arguments.addAll(args);
+                calcManager.removeWorkersForName(calcName);
+                var worker = createWorker(arguments, frame, calcManager);
+                calcManager.registerWorker(worker);
+              }
+            });
+      });
+      parent.add(_editItem);
+    }
+    final var editItem = _editItem;
+
+    parent.addMenuListener(new MenuListener()
+      {
+        @Override
+        public void menuSelected(MenuEvent e)
+        {
+          var isNuc = frame.getViewport().getAlignment().isNucleotide();
+          var menuEnabled = (isNuc && operation.isNucleotideOperation()) ||
+              (!isNuc && operation.isProteinOperation());
+          runItem.setEnabled(menuEnabled);
+          if (editItem != null)
+            editItem.setEnabled(menuEnabled);
+          boolean currentlyRunning = calcManager.getWorkersForName(calcName).size() > 0;
+          runItem.setSelected(currentlyRunning);
+        }
+
+        @Override
+        public void menuDeselected(MenuEvent e) {}
+
+        @Override
+        public void menuCanceled(MenuEvent e) {}
+      });
+  }
+  
+
+  private CompletionStage<List<ArgumentI>> openEditParamsDialog(
+          ParamDatastoreI paramStore, WsParamSetI preset,
+          List<ArgumentI> arguments)
+  {
+    WsJobParameters jobParams;
+    if (preset == null && arguments != null && arguments.size() > 0)
+      jobParams = new WsJobParameters(paramStore, preset, arguments);
+    else
+      jobParams = new WsJobParameters(paramStore, preset, null);
+    if (preset != null)
+    {
+      jobParams.setName(MessageManager.getString(
+          "label.adjusting_parameters_for_calculation"));
+    }
+    var stage = jobParams.showRunDialog();
+    return stage.thenApply((startJob) -> {
+      if (startJob)
+      {
+        if (jobParams.getPreset() == null)
+        {
+          return jobParams.getJobParams();
+        }
+        else
+        {
+          return jobParams.getPreset().getArguments();
+        }
+      }
+      else
+      {
+        return null;
+      }
+    });
+  }
+  
+
+  private AnnotationServiceWorker createWorker(
+      List<ArgumentI> arguments, AlignFrame frame, AlignCalcManagerI2 calcManager)
+  {
+    /* What is the purpose of AlignViewport and AlignmentViewPanel? */
+    AlignViewport viewport = frame.getCurrentView();
+    AlignmentViewPanel alignPanel = frame.alignPanel;
+    return new AnnotationServiceWorker(operation,
+        arguments, viewport, alignPanel, frame, frame,
+        calcManager);
+  }
+
+}