gradle: add CLI-style task execution action appcode/140.1006 clion/140.1007
authorVladislav.Soroka <Vladislav.Soroka@jetbrains.com>
Mon, 8 Dec 2014 08:52:51 +0000 (11:52 +0300)
committerVladislav.Soroka <Vladislav.Soroka@jetbrains.com>
Mon, 8 Dec 2014 09:00:15 +0000 (12:00 +0300)
21 files changed:
platform/external-system-api/src/com/intellij/openapi/externalSystem/model/execution/ExternalSystemTaskExecutionSettings.java
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemTaskSettingsControl.java
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java [new file with mode: 0644]
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/cmd/CommandLineCompletionProvider.java [moved from plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/cmd/CommandLineCompletionProvider.java with 97% similarity]
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/cmd/ParametersListLexer.java [moved from plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/cmd/ParametersListLexer.java with 94% similarity]
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/ExternalSystemNotificationManager.java
platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/notification/NotificationSource.java
plugins/gradle/gradle.iml
plugins/gradle/lib/gradle-cli-2.2.jar [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleArgumentsCompletionProvider.java [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsConverter.java [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsProvider.java [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/ExecuteGradleTaskHistoryService.java [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.form [new file with mode: 0644]
plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.java [new file with mode: 0644]
plugins/maven/maven.iml
plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenArgumentsCompletionProvider.java
plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerParametersPanel.java
plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/actions/MavenActionUtil.java

index ad9dec8d1fe1f81779fdfc6944bec9249ac867a4..fb7d8e1c0b0e21c958b5521ba32ca5e113171d3b 100644 (file)
@@ -160,4 +160,11 @@ public class ExternalSystemTaskExecutionSettings implements Cloneable {
 
     return true;
   }
+
+  @Override
+  public String toString() {
+    return (myTaskNames == null ? "" : StringUtil.join(myTaskNames, " ")) +
+           (StringUtil.isEmpty(myScriptParameters) ? "" : " " + myScriptParameters) +
+           (StringUtil.isEmpty(myVmOptions) ? "" : " " + myVmOptions);
+  }
 }
index eca62e509a4773ce4d298a2ca06c229355cf7715..8ef61375a42e82125b86434fa998e311f57154f1 100644 (file)
@@ -151,7 +151,6 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
     public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
       if (myProject.isDisposed()) return null;
 
-      ExternalSystemUtil.updateRecentTasks(new ExternalTaskExecutionInfo(mySettings.clone(), executor.getId()), myProject);
       final List<ExternalTaskPojo> tasks = ContainerUtilRt.newArrayList();
       for (String taskName : mySettings.getTaskNames()) {
         tasks.add(new ExternalTaskPojo(taskName, mySettings.getExternalProjectPath(), null));
@@ -188,11 +187,11 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
           final String greeting;
           if (mySettings.getTaskNames().size() > 1) {
             greeting = ExternalSystemBundle
-              .message("run.text.starting.multiple.task", startDateTime, StringUtil.join(mySettings.getTaskNames(), " "));
+              .message("run.text.starting.multiple.task", startDateTime, mySettings.toString());
           }
           else {
             greeting =
-              ExternalSystemBundle.message("run.text.starting.single.task", startDateTime, StringUtil.join(mySettings.getTaskNames(), " "));
+              ExternalSystemBundle.message("run.text.starting.single.task", startDateTime, mySettings.toString());
           }
           processHandler.notifyTextAvailable(greeting, ProcessOutputTypes.SYSTEM);
           task.execute(new ExternalSystemTaskNotificationListenerAdapter() {
@@ -223,11 +222,11 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
               final String farewell;
               if (mySettings.getTaskNames().size() > 1) {
                 farewell = ExternalSystemBundle
-                  .message("run.text.ended.multiple.task", endDateTime, StringUtil.join(mySettings.getTaskNames(), " "));
+                  .message("run.text.ended.multiple.task", endDateTime, mySettings.toString());
               }
               else {
                 farewell =
-                  ExternalSystemBundle.message("run.text.ended.single.task", endDateTime, StringUtil.join(mySettings.getTaskNames(), " "));
+                  ExternalSystemBundle.message("run.text.ended.single.task", endDateTime, mySettings.toString());
               }
               processHandler.notifyTextAvailable(farewell, ProcessOutputTypes.SYSTEM);
               processHandler.notifyProcessTerminated(0);
@@ -243,7 +242,6 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
 
   private static class MyProcessHandler extends ProcessHandler {
     private final ExternalSystemExecuteTaskTask myTask;
-    @Nullable private volatile OutputStream myOutputStream;
 
     public MyProcessHandler(ExternalSystemExecuteTaskTask task) {
       myTask = task;
index 4e7a87e1d53af5b6efe38ea59d6a996e4416e716..8bb868f30aa14336607a1b1851ee3cc94f930475 100644 (file)
@@ -23,10 +23,12 @@ import com.intellij.openapi.externalSystem.service.ui.ExternalProjectPathField;
 import com.intellij.openapi.externalSystem.util.*;
 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
 import com.intellij.openapi.options.ConfigurationException;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.EditorTextField;
 import com.intellij.ui.RawCommandLineEditor;
 import com.intellij.ui.components.JBLabel;
 import com.intellij.ui.components.JBTextField;
@@ -52,7 +54,7 @@ public class ExternalSystemTaskSettingsControl implements ExternalSystemSettings
   private ExternalProjectPathField myProjectPathField;
   @SuppressWarnings("FieldCanBeLocal") // Used via reflection at showUi() and disposeResources()
   private JBLabel myTasksLabel;
-  private JBTextField myTasksTextField;
+  private EditorTextField myTasksTextField;
   @SuppressWarnings("FieldCanBeLocal") // Used via reflection at showUi() and disposeResources()
   private JBLabel myVmOptionsLabel;
   private RawCommandLineEditor myVmOptionsEditor;
@@ -95,12 +97,14 @@ public class ExternalSystemTaskSettingsControl implements ExternalSystemSettings
     canvas.add(myProjectPathField, ExternalSystemUiUtil.getFillLineConstraints(0));
 
     myTasksLabel = new JBLabel(ExternalSystemBundle.message("run.configuration.settings.label.tasks"));
-    myTasksTextField = new JBTextField(ExternalSystemConstants.TEXT_FIELD_WIDTH_IN_COLUMNS);
+    myTasksTextField = new EditorTextField("", myProject, PlainTextFileType.INSTANCE);
     canvas.add(myTasksLabel, ExternalSystemUiUtil.getLabelConstraints(0));
     GridBag c = ExternalSystemUiUtil.getFillLineConstraints(0);
     c.insets.right = myProjectPathField.getButton().getPreferredSize().width + 8 /* street magic, sorry */;
     canvas.add(myTasksTextField, c);
 
+    new TaskCompletionProvider(myProject, myExternalSystemId, myProjectPathField).apply(myTasksTextField);
+
     myVmOptionsLabel = new JBLabel(ExternalSystemBundle.message("run.configuration.settings.label.vmoptions"));
     myVmOptionsEditor = new RawCommandLineEditor();
     myVmOptionsEditor.setDialogCaption(ExternalSystemBundle.message("run.configuration.settings.label.vmoptions"));
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/TaskCompletionProvider.java
new file mode 100644 (file)
index 0000000..0156e96
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.externalSystem.service.execution;
+
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.openapi.externalSystem.model.DataNode;
+import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
+import com.intellij.openapi.externalSystem.model.ProjectKeys;
+import com.intellij.openapi.externalSystem.model.ProjectSystemId;
+import com.intellij.openapi.externalSystem.model.project.ModuleData;
+import com.intellij.openapi.externalSystem.model.task.TaskData;
+import com.intellij.openapi.externalSystem.service.execution.cmd.CommandLineCompletionProvider;
+import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
+import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.TextAccessor;
+import com.intellij.util.BooleanFunction;
+import com.intellij.util.containers.ContainerUtil;
+import groovyjarjarcommonscli.Options;
+import icons.ExternalSystemIcons;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/26/2014
+ */
+public class TaskCompletionProvider extends CommandLineCompletionProvider {
+
+  private volatile List<LookupElement> myCachedElements;
+  private volatile String myCachedWorkingDir;
+  private final Project myProject;
+  private final ProjectSystemId mySystemId;
+  private final TextAccessor myProjectPathAccessor;
+
+
+  public TaskCompletionProvider(@NotNull Project project,
+                                @NotNull ProjectSystemId externalSystemId,
+                                @NotNull TextAccessor workDirectoryField) {
+    this(project, externalSystemId, workDirectoryField, new Options());
+  }
+
+  public TaskCompletionProvider(@NotNull Project project,
+                                @NotNull ProjectSystemId externalSystemId,
+                                @NotNull TextAccessor workDirectoryField,
+                                @NotNull Options options) {
+    super(options);
+    myProject = project;
+    mySystemId = externalSystemId;
+    myProjectPathAccessor = workDirectoryField;
+  }
+
+  @Override
+  protected void addArgumentVariants(@NotNull CompletionResultSet result) {
+    List<LookupElement> cachedElements = myCachedElements;
+    final String projectPath = myProjectPathAccessor.getText();
+    if (cachedElements == null || !StringUtil.equals(myCachedWorkingDir, projectPath)) {
+      final ExternalProjectSettings linkedProjectSettings =
+        ExternalSystemApiUtil.getSettings(myProject, mySystemId).getLinkedProjectSettings(projectPath);
+      if (linkedProjectSettings == null) return;
+
+      final ExternalProjectInfo projectData =
+        ProjectDataManager.getInstance().getExternalProjectData(myProject, mySystemId, linkedProjectSettings.getExternalProjectPath());
+
+      if (projectData == null || projectData.getExternalProjectStructure() == null) return;
+
+      final DataNode<?> node =
+        ExternalSystemApiUtil.findFirstRecursively(projectData.getExternalProjectStructure(), new BooleanFunction<DataNode<?>>() {
+          @Override
+          public boolean fun(DataNode<?> node) {
+            return node.getKey().equals(ProjectKeys.MODULE) &&
+                   node.getData() instanceof ModuleData &&
+                   ((ModuleData)node.getData()).getLinkedExternalProjectPath().equals(projectPath);
+          }
+        });
+
+      final Collection<DataNode<TaskData>> tasks = ExternalSystemApiUtil.getChildren(node, ProjectKeys.TASK);
+      cachedElements = ContainerUtil.newArrayListWithCapacity(tasks.size());
+      for (DataNode<TaskData> taskDataNode : tasks) {
+        cachedElements.add(LookupElementBuilder.create(taskDataNode.getData().getName()).withIcon(ExternalSystemIcons.Task));
+      }
+      myCachedElements = cachedElements;
+      myCachedWorkingDir = projectPath;
+    }
+    result.addAllElements(cachedElements);
+  }
+}
+
index 75a227518b4690cd4abd836dfe3b7959e025ed37..aa37b6b1b600aa991ecc8ebded5ba60577d4502e 100644 (file)
@@ -13,16 +13,17 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager;
 import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
 import com.intellij.openapi.externalSystem.model.LocationAwareExternalSystemException;
 import com.intellij.openapi.externalSystem.model.ProjectSystemId;
+import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
 import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
 import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
 import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
+import com.intellij.openapi.externalSystem.view.ExternalProjectsView;
 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.wm.ToolWindow;
 import com.intellij.openapi.wm.ToolWindowId;
@@ -148,8 +149,15 @@ public class ExternalSystemNotificationManager {
           }
         }
 
-        final NotificationGroup group = ExternalSystemUtil.getToolWindowElement(
-          NotificationGroup.class, myProject, ExternalSystemDataKeys.NOTIFICATION_GROUP, externalSystemId);
+        NotificationGroup group;
+        if (notificationData.getBalloonGroup() == null) {
+          ExternalProjectsView externalProjectsView = ExternalProjectsManager.getInstance(myProject).getExternalProjectsView(externalSystemId);
+          group = externalProjectsView != null ? externalProjectsView.getNotificationGroup() : null;
+        }
+        else {
+          final NotificationGroup registeredGroup = NotificationGroup.findRegisteredGroup(notificationData.getBalloonGroup());
+          group = registeredGroup != null ? registeredGroup : NotificationGroup.balloonGroup(notificationData.getBalloonGroup());
+        }
         if (group == null) return;
 
         final Notification notification = group.createNotification(
@@ -360,6 +368,10 @@ public class ExternalSystemNotificationManager {
         contentDisplayName =
           ExternalSystemBundle.message("notification.messages.project.sync.tab.name", externalSystemId.getReadableName());
         break;
+      case TASK_EXECUTION:
+        contentDisplayName =
+          ExternalSystemBundle.message("notification.messages.task.execution.tab.name", externalSystemId.getReadableName());
+        break;
       default:
         throw new AssertionError("unsupported notification source found: " + notificationSource);
     }
index 4a20167c778cb352880a7b1607471b8c3efed12b..e88075e185b16d26fcc2cccd857947015b617481 100644 (file)
@@ -20,5 +20,5 @@ package com.intellij.openapi.externalSystem.service.notification;
  * @since 3/28/14
  */
 public enum NotificationSource {
-  PROJECT_SYNC
+  PROJECT_SYNC, TASK_EXECUTION
 }
index b817051efbc939087225cddc3d3d17a8fcdf8127..eb7b491bad708f807942a742e7d95e5dd8166258 100644 (file)
@@ -40,6 +40,7 @@
           <root url="jar://$MODULE_DIR$/lib/gradle-base-services-groovy-2.2.jar!/" />
           <root url="jar://$MODULE_DIR$/lib/gradle-native-2.2.jar!/" />
           <root url="jar://$MODULE_DIR$/lib/gradle-resources-2.2.jar!/" />
+          <root url="jar://$MODULE_DIR$/lib/gradle-cli-2.2.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
@@ -53,6 +54,7 @@
           <root url="jar://$MODULE_DIR$/lib/gradle-2.2-src.zip!/gradle-2.2/subprojects/base-services-groovy/src/main/groovy" />
           <root url="jar://$MODULE_DIR$/lib/gradle-2.2-src.zip!/gradle-2.2/subprojects/native/src/main/java" />
           <root url="jar://$MODULE_DIR$/lib/gradle-2.2-src.zip!/gradle-2.2/subprojects/resources/src/main/java" />
+          <root url="jar://$MODULE_DIR$/lib/gradle-2.2-src.zip!/gradle-2.2/subprojects/cli/src/main/java" />
         </SOURCES>
       </library>
     </orderEntry>
diff --git a/plugins/gradle/lib/gradle-cli-2.2.jar b/plugins/gradle/lib/gradle-cli-2.2.jar
new file mode 100644 (file)
index 0000000..8d675c2
Binary files /dev/null and b/plugins/gradle/lib/gradle-cli-2.2.jar differ
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleExecuteTaskAction.java
new file mode 100644 (file)
index 0000000..e0a61b4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.action;
+
+import com.intellij.execution.RunManagerEx;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.executors.DefaultRunExecutor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil;
+import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
+import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
+import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
+import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware;
+import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager;
+import com.intellij.openapi.externalSystem.service.notification.NotificationCategory;
+import com.intellij.openapi.externalSystem.service.notification.NotificationData;
+import com.intellij.openapi.externalSystem.service.notification.NotificationSource;
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
+import com.intellij.openapi.externalSystem.view.ExternalSystemNode;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.Function;
+import org.gradle.cli.CommandLineArgumentException;
+import org.gradle.cli.CommandLineParser;
+import org.gradle.cli.ParsedCommandLine;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.service.execution.cmd.GradleCommandLineOptionsConverter;
+import org.jetbrains.plugins.gradle.service.task.ExecuteGradleTaskHistoryService;
+import org.jetbrains.plugins.gradle.service.task.GradleRunTaskDialog;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/25/2014
+ */
+public class GradleExecuteTaskAction extends DumbAwareAction {
+  @Override
+  public void actionPerformed(@NotNull final AnActionEvent e) {
+    final Project project = e.getRequiredData(CommonDataKeys.PROJECT);
+    ExecuteGradleTaskHistoryService historyService = ExecuteGradleTaskHistoryService.getInstance(project);
+    GradleRunTaskDialog dialog = new GradleRunTaskDialog(project, historyService.getHistory());
+    String lastWorkingDirectory = historyService.getWorkDirectory();
+    if (lastWorkingDirectory.length() == 0) {
+      lastWorkingDirectory = obtainAppropriateWorkingDirectory(e);
+    }
+
+    dialog.setWorkDirectory(lastWorkingDirectory);
+
+    if (StringUtil.isEmptyOrSpaces(historyService.getCanceledCommand())) {
+      if (historyService.getHistory().size() > 0) {
+        dialog.setCommandLine(historyService.getHistory().get(0));
+      }
+    }
+    else {
+      dialog.setCommandLine(historyService.getCanceledCommand());
+    }
+
+    if (!dialog.showAndGet()) {
+      historyService.setCanceledCommand(dialog.getCommandLine());
+      return;
+    }
+
+    historyService.setCanceledCommand(null);
+
+    String fullCommandLine = dialog.getCommandLine();
+    fullCommandLine = fullCommandLine.trim();
+
+    String workDirectory = dialog.getWorkDirectory();
+
+    historyService.addCommand(fullCommandLine, workDirectory);
+
+    final ExternalTaskExecutionInfo taskExecutionInfo;
+    try {
+      taskExecutionInfo = buildTaskInfo(workDirectory, fullCommandLine);
+    }
+    catch (CommandLineArgumentException ex) {
+      final NotificationData notificationData = new NotificationData(
+        "<b>Command-line arguments cannot be parsed</b>",
+        "<i>" + fullCommandLine + "</i> \n" + ex.getMessage(),
+        NotificationCategory.WARNING, NotificationSource.TASK_EXECUTION
+      );
+      notificationData.setBalloonNotification(true);
+      ExternalSystemNotificationManager.getInstance(project).showNotification(GradleConstants.SYSTEM_ID, notificationData);
+      return;
+    }
+    RunManagerEx runManager = RunManagerEx.getInstanceEx(project);
+
+    ExternalSystemUtil.runTask(taskExecutionInfo.getSettings(), taskExecutionInfo.getExecutorId(), project, GradleConstants.SYSTEM_ID);
+
+    RunnerAndConfigurationSettings configuration =
+      ExternalSystemUtil.createExternalSystemRunnerAndConfigurationSettings(taskExecutionInfo.getSettings(),
+                                                                            project, GradleConstants.SYSTEM_ID);
+    if (configuration == null) return;
+
+    final RunnerAndConfigurationSettings existingConfiguration = runManager.findConfigurationByName(configuration.getName());
+    if(existingConfiguration == null) {
+      runManager.setTemporaryConfiguration(configuration);
+    } else {
+      runManager.setSelectedConfiguration(existingConfiguration);
+    }
+  }
+
+  private static ExternalTaskExecutionInfo buildTaskInfo(@NotNull String projectPath, @NotNull String fullCommandLine)
+    throws CommandLineArgumentException {
+    CommandLineParser gradleCmdParser = new CommandLineParser();
+
+    GradleCommandLineOptionsConverter commandLineConverter = new GradleCommandLineOptionsConverter();
+    commandLineConverter.configure(gradleCmdParser);
+    ParsedCommandLine parsedCommandLine = gradleCmdParser.parse(StringUtil.split(fullCommandLine, " "));
+
+    final Map<String, List<String>> optionsMap =
+      commandLineConverter.convert(parsedCommandLine, new HashMap<String, List<String>>());
+
+    final List<String> systemProperties = optionsMap.remove("system-prop");
+    final String vmOptions = systemProperties == null ? "" : StringUtil.join(systemProperties, new Function<String, String>() {
+      @Override
+      public String fun(String entry) {
+        return "-D" + entry;
+      }
+    }, " ");
+
+    final String scriptParameters = StringUtil.join(optionsMap.entrySet(), new Function<Map.Entry<String, List<String>>, String>() {
+      @Override
+      public String fun(Map.Entry<String, List<String>> entry) {
+        final List<String> values = entry.getValue();
+        final String longOptionName = entry.getKey();
+        if (values != null && !values.isEmpty()) {
+          return StringUtil.join(values, new Function<String, String>() {
+            @Override
+            public String fun(String entry) {
+              return "--" + longOptionName + ' ' + entry;
+            }
+          }, " ");
+        }
+        else {
+          return "--" + longOptionName;
+        }
+      }
+    }, " ");
+
+    final List<String> tasks = parsedCommandLine.getExtraArguments();
+
+    ExternalSystemTaskExecutionSettings settings = new ExternalSystemTaskExecutionSettings();
+    settings.setExternalProjectPath(projectPath);
+    settings.setTaskNames(tasks);
+    settings.setScriptParameters(scriptParameters);
+    settings.setVmOptions(vmOptions);
+    settings.setExternalSystemIdString(GradleConstants.SYSTEM_ID.toString());
+    return new ExternalTaskExecutionInfo(settings, DefaultRunExecutor.EXECUTOR_ID);
+  }
+
+  private static String obtainAppropriateWorkingDirectory(AnActionEvent e) {
+    final List<ExternalSystemNode> selectedNodes = ExternalSystemDataKeys.SELECTED_NODES.getData(e.getDataContext());
+    if (selectedNodes == null || selectedNodes.size() != 1) {
+      final Module module = ExternalSystemActionUtil.getModule(e.getDataContext());
+      String projectPath = ExternalSystemApiUtil.getExternalProjectPath(module);
+      return projectPath == null ? "" : projectPath;
+    }
+
+    final ExternalSystemNode<?> node = selectedNodes.get(0);
+    final Object externalData = node.getData();
+    if (externalData instanceof ExternalConfigPathAware) {
+      return ((ExternalConfigPathAware)externalData).getLinkedExternalProjectPath();
+    }
+    else {
+      final ExternalConfigPathAware parentExternalConfigPathAware = node.findParentData(ExternalConfigPathAware.class);
+      return parentExternalConfigPathAware != null ? parentExternalConfigPathAware.getLinkedExternalProjectPath() : "";
+    }
+  }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleArgumentsCompletionProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleArgumentsCompletionProvider.java
new file mode 100644 (file)
index 0000000..bf04490
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.service.execution;
+
+import com.intellij.openapi.externalSystem.service.execution.TaskCompletionProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.TextAccessor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.service.execution.cmd.GradleCommandLineOptionsProvider;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/25/2014
+ */
+public class GradleArgumentsCompletionProvider extends TaskCompletionProvider {
+
+  public GradleArgumentsCompletionProvider(@NotNull Project project, @NotNull TextAccessor workDirectoryField) {
+    super(project, GradleConstants.SYSTEM_ID, workDirectoryField, GradleCommandLineOptionsProvider.getSupportedOptions());
+  }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsConverter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsConverter.java
new file mode 100644 (file)
index 0000000..a3763f6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.service.execution.cmd;
+
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.ContainerUtil;
+import groovyjarjarcommonscli.Option;
+import org.gradle.cli.*;
+import org.jetbrains.plugins.gradle.service.execution.GradleArgumentsCompletionProvider;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/25/2014
+ */
+public class GradleCommandLineOptionsConverter extends AbstractCommandLineConverter<Map<String, List<String>>> {
+
+  private final SystemPropertiesCommandLineConverter systemPropertiesCommandLineConverter = new SystemPropertiesCommandLineConverter();
+
+  @Override
+  public Map<String, List<String>> convert(ParsedCommandLine options, Map<String, List<String>> target)
+    throws CommandLineArgumentException {
+    //noinspection unchecked
+    final Collection<Option> supportedOptions = GradleCommandLineOptionsProvider.getSupportedOptions().getOptions();
+    for (Option supportedOption : supportedOptions) {
+      final String longOpt = supportedOption.getLongOpt();
+      if (longOpt != null && options.hasOption(longOpt)) {
+        final ParsedCommandLineOption option = options.option(longOpt);
+        target.put(longOpt, option.getValues());
+      }
+      else {
+        final String opt = supportedOption.getOpt();
+        if (opt != null && options.hasOption(opt)) {
+          final ParsedCommandLineOption option = options.option(opt);
+          target.put(opt, option.getValues());
+        }
+      }
+    }
+
+    return target;
+  }
+
+  @Override
+  public void configure(CommandLineParser parser) {
+    systemPropertiesCommandLineConverter.configure(parser);
+    parser.allowMixedSubcommandsAndOptions();
+
+    //noinspection unchecked
+    final Collection<Option> supportedOptions = GradleCommandLineOptionsProvider.getSupportedOptions().getOptions();
+    for (Option supportedOption : supportedOptions) {
+
+
+      final List<String> objects = ContainerUtil.newSmartList();
+      ContainerUtil.addAllNotNull(objects, supportedOption.getOpt(), supportedOption.getLongOpt());
+
+      if (!objects.isEmpty()) {
+        try {
+          final CommandLineOption option = parser.option(ArrayUtil.toStringArray(objects));
+          if (supportedOption.hasArg()) {
+            option.hasArgument();
+          }
+
+          if (supportedOption.hasArgs()) {
+            option.hasArguments();
+          }
+          option.hasDescription(supportedOption.getDescription());
+        }
+        catch (IllegalArgumentException ignore) {
+        }
+      }
+    }
+  }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/cmd/GradleCommandLineOptionsProvider.java
new file mode 100644 (file)
index 0000000..f0eacda
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.service.execution.cmd;
+
+import groovyjarjarcommonscli.OptionBuilder;
+import groovyjarjarcommonscli.Options;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/26/2014
+ */
+@SuppressWarnings("AccessStaticViaInstance")
+public class GradleCommandLineOptionsProvider {
+
+  private static final Options ourOptions;
+
+  static {
+    Options options = new Options();
+    options.addOption(OptionBuilder.withLongOpt("no-rebuild").withDescription("Do not rebuild project dependencies.").create('a'));
+    options.addOption(OptionBuilder.withLongOpt("settings-file").withDescription("Specifies the settings file.").hasArg().create('c'));
+    options.addOption(OptionBuilder.withLongOpt("continue").withDescription("Continues task execution after a task failure.").create());
+    options.addOption(OptionBuilder.withLongOpt("configure-on-demand").withDescription(
+      "Only relevant projects are configured in this build run. This means faster builds for large multi-projects.").create());
+    options.addOption(
+      OptionBuilder.withLongOpt("system-prop").withDescription("Sets a system property of the JVM, for example -Dmyprop=myvalue.")
+        .hasArg().create('D'));
+    options.addOption(OptionBuilder.withLongOpt("debug").withDescription("Log in debug mode (includes normal stacktrace).").create('d'));
+    options.addOption(OptionBuilder.withLongOpt("gradle-user-home").withDescription(
+      "Specifies the Gradle user home directory. The default is the .gradle directory in the user's home directory.").hasArg().create('g'));
+    options
+      .addOption(OptionBuilder.withLongOpt("init-script").withDescription("Specifies an initialization script. ").hasArg().create('I'));
+    options.addOption(OptionBuilder.withLongOpt("info").withDescription("Set log level to info. ").create('i'));
+    options.addOption(OptionBuilder.withLongOpt("dry-run").withDescription("Runs the build with all task actions disabled. ").create('m'));
+    options.addOption(
+      OptionBuilder.withLongOpt("offline").withDescription("Specifies that the build should operate without accessing network resources.")
+        .create());
+    options.addOption(OptionBuilder.withLongOpt("project-prop")
+                        .withDescription("Sets a project property of the root project, for example -Pmyprop=myvalue.").hasArgs()
+                        .create('P'));
+    options.addOption(
+      OptionBuilder.withLongOpt("project-dir").withDescription("Specifies the start directory for Gradle. Defaults to current directory.")
+        .hasArg().create('p'));
+    options.addOption(OptionBuilder.withLongOpt("parallel").withDescription(
+      "Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use. This option should only be used with decoupled projects")
+                        .create());
+    options.addOption(OptionBuilder.withLongOpt("parallel-threads").withDescription(
+      "Build projects in parallel, using the specified number of executor threads. For example--parallel-threads=3. This option should only be used with decoupled projects")
+                        .hasArg().create());
+    options.addOption(OptionBuilder.withLongOpt("profile")
+                        .withDescription("Profiles build execution time and generates a report in the buildDir/reports/profile directory.")
+                        .create());
+    options.addOption(OptionBuilder.withLongOpt("project-cache-dir").withDescription(
+      "Specifies the project-specific cache directory. Default value is .gradle in the root project directory.").hasArg().create());
+    options.addOption(OptionBuilder.withLongOpt("quiet").withDescription("Log errors only.").create('q'));
+    options.addOption(OptionBuilder.withLongOpt("recompile-scripts")
+                        .withDescription("Specifies that cached build scripts are skipped and forced to be recompiled.").create());
+    options.addOption(OptionBuilder.withLongOpt("refresh-dependencies").withDescription("Refresh the state of dependencies.").create());
+    options
+      .addOption(OptionBuilder.withLongOpt("rerun-tasks").withDescription("Specifies that any task optimization is ignored.").create());
+    options.addOption(
+      OptionBuilder.withLongOpt("full-stacktrace").withDescription("Print out the full (very verbose) stacktrace for any exceptions.")
+        .create('S'));
+    options.addOption(
+      OptionBuilder.withLongOpt("stacktrace").withDescription("Print out the stacktrace also for user exceptions (e.g. compile error).")
+        .create('s'));
+    options.addOption(
+      OptionBuilder.withLongOpt("no-search-upwards").withDescription("Don't search in parent directories for a settings.gradle file.")
+        .create('u'));
+    options
+      .addOption(
+        OptionBuilder.withLongOpt("exclude-task").withDescription("Specifies a task to be excluded from execution.").hasArgs().create('x'));
+
+    // Do not uncomment the following options. These options does not supported via tooling API.
+    //options.addOption(OptionBuilder.withLongOpt("build-file").withDescription("Specifies the build file.").hasArg().create('b'));
+    //options.addOption(OptionBuilder.withLongOpt("help").withDescription("Shows a help message.").create('h'));
+    //options.addOption(OptionBuilder.withLongOpt("version").withDescription("Prints version info.").create('v'));
+    //options.addOption(OptionBuilder.withLongOpt("all").withDescription("Shows additional detail in the task listing. See Section 11.6.2, “Listing tasks”.").create());
+
+    ourOptions = options;
+  }
+
+  public static Options getSupportedOptions() {
+    return ourOptions;
+  }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/ExecuteGradleTaskHistoryService.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/ExecuteGradleTaskHistoryService.java
new file mode 100644 (file)
index 0000000..8c81013
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.service.task;
+
+import com.intellij.openapi.components.*;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 11/25/2014
+ */
+@State(
+  name = "gradleExecuteTaskHistory",
+  storages = @Storage(file = StoragePathMacros.WORKSPACE_FILE)
+)
+public class ExecuteGradleTaskHistoryService implements PersistentStateComponent<String[]> {
+
+  private static final int MAX_HISTORY_LENGTH = 20;
+  private final LinkedList<String> myHistory = new LinkedList<String>();
+  private String myWorkDirectory = "";
+  private String myCanceledCommand;
+
+  public static ExecuteGradleTaskHistoryService getInstance(@NotNull Project project) {
+    return ServiceManager.getService(project, ExecuteGradleTaskHistoryService.class);
+  }
+
+  @Nullable
+  public String getCanceledCommand() {
+    return myCanceledCommand;
+  }
+
+  public void setCanceledCommand(@Nullable String canceledCommand) {
+    myCanceledCommand = canceledCommand;
+  }
+
+  public void addCommand(@NotNull String command, @NotNull String projectPath) {
+    myWorkDirectory = projectPath.trim();
+
+    command = command.trim();
+
+    if (command.length() == 0) return;
+
+    myHistory.remove(command);
+    myHistory.addFirst(command);
+
+    while (myHistory.size() > MAX_HISTORY_LENGTH) {
+      myHistory.removeLast();
+    }
+  }
+
+  public List<String> getHistory() {
+    return new ArrayList<String>(myHistory);
+  }
+
+  @NotNull
+  public String getWorkDirectory() {
+    return myWorkDirectory;
+  }
+
+  @Nullable
+  @Override
+  public String[] getState() {
+    String[] res = new String[myHistory.size() + 1];
+    res[0] = myWorkDirectory;
+
+    int i = 1;
+    for (String goal : myHistory) {
+      res[i++] = goal;
+    }
+
+    return res;
+  }
+
+  @Override
+  public void loadState(String[] state) {
+    if (state.length == 0) {
+      myWorkDirectory = "";
+      myHistory.clear();
+    }
+    else {
+      myWorkDirectory = state[0];
+      myHistory.addAll(Arrays.asList(state).subList(1, state.length));
+    }
+  }
+}
\ No newline at end of file
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.form b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.form
new file mode 100644 (file)
index 0000000..924661e
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.gradle.service.task.GradleRunTaskDialog">
+  <grid id="cbd77" binding="contentPane" layout-manager="BorderLayout" hgap="10" vgap="10">
+    <constraints>
+      <xy x="48" y="54" width="793" height="297"/>
+    </constraints>
+    <properties/>
+    <border type="none">
+      <font/>
+    </border>
+    <children>
+      <grid id="34d93" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints border-constraint="North"/>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="f4093" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="Gradle &amp;project"/>
+            </properties>
+          </component>
+          <component id="8a07" class="javax.swing.JLabel" binding="commandLineLabel">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="&amp;Command line"/>
+            </properties>
+          </component>
+          <grid id="415e7" binding="projectPathFieldPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children/>
+          </grid>
+          <grid id="c6ac5" binding="commandLinePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
+            <constraints>
+              <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+                <preferred-size width="600" height="-1"/>
+              </grid>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children/>
+          </grid>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleRunTaskDialog.java
new file mode 100644 (file)
index 0000000..75b293d
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.service.task;
+
+import com.intellij.openapi.externalSystem.ExternalSystemManager;
+import com.intellij.openapi.externalSystem.ExternalSystemUiAware;
+import com.intellij.openapi.externalSystem.service.ui.ExternalProjectPathField;
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
+import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.ui.EditorComboBoxEditor;
+import com.intellij.ui.EditorComboBoxRenderer;
+import com.intellij.ui.EditorTextField;
+import com.intellij.ui.StringComboboxEditor;
+import com.intellij.util.ArrayUtilRt;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.gradle.service.execution.GradleArgumentsCompletionProvider;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Collection;
+
+public class GradleRunTaskDialog extends DialogWrapper {
+
+  private final Project myProject;
+  @Nullable private final Collection<String> myHistory;
+
+  private JPanel contentPane;
+
+  private ExternalProjectPathField myProjectPathField;
+
+  private JPanel commandLinePanel;
+  private JLabel commandLineLabel;
+  private JPanel projectPathFieldPanel;
+  private ComboBox commandLineComboBox;
+  private EditorTextField commandLineEditor;
+
+
+  public GradleRunTaskDialog(@NotNull Project project) {
+    this(project, null);
+  }
+
+  public GradleRunTaskDialog(@NotNull Project project, @Nullable Collection<String> history) {
+    super(project, true);
+    myProject = project;
+    myHistory = history;
+
+    setTitle("Run Gradle Task");
+    setUpDialog();
+    setModal(true);
+    init();
+  }
+
+  private void setUpDialog() {
+    JComponent commandLineComponent;
+    if (myHistory == null) {
+      commandLineEditor = new EditorTextField("", myProject, PlainTextFileType.INSTANCE);
+      commandLineComponent = commandLineEditor;
+
+      commandLineLabel.setLabelFor(commandLineEditor);
+    }
+    else {
+      commandLineComboBox = new ComboBox(ArrayUtilRt.toStringArray(myHistory));
+      commandLineComponent = commandLineComboBox;
+
+      commandLineLabel.setLabelFor(commandLineComboBox);
+
+      commandLineComboBox.setLightWeightPopupEnabled(false);
+
+      EditorComboBoxEditor editor = new StringComboboxEditor(myProject, PlainTextFileType.INSTANCE, commandLineComboBox);
+      //noinspection GtkPreferredJComboBoxRenderer
+      commandLineComboBox.setRenderer(new EditorComboBoxRenderer(editor));
+
+      commandLineComboBox.setEditable(true);
+      commandLineComboBox.setEditor(editor);
+      commandLineComboBox.setFocusable(true);
+
+      commandLineEditor = editor.getEditorComponent();
+    }
+
+    commandLinePanel.add(commandLineComponent);
+
+    ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(GradleConstants.SYSTEM_ID);
+    FileChooserDescriptor projectPathChooserDescriptor = null;
+    if (manager instanceof ExternalSystemUiAware) {
+      projectPathChooserDescriptor = ((ExternalSystemUiAware)manager).getExternalProjectConfigDescriptor();
+    }
+    if (projectPathChooserDescriptor == null) {
+      projectPathChooserDescriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor();
+    }
+
+    String title = ExternalSystemBundle.message("settings.label.select.project", GradleConstants.SYSTEM_ID.getReadableName());
+    myProjectPathField = new ExternalProjectPathField(myProject, GradleConstants.SYSTEM_ID, projectPathChooserDescriptor, title) {
+      @Override
+      public Dimension getPreferredSize() {
+        return commandLinePanel == null ? super.getPreferredSize() : commandLinePanel.getPreferredSize();
+      }
+    };
+
+    projectPathFieldPanel.add(myProjectPathField);
+
+    new GradleArgumentsCompletionProvider(myProject, myProjectPathField).apply(commandLineEditor);
+  }
+
+  @Nullable
+  @Override
+  protected ValidationInfo doValidate() {
+    if (myProjectPathField.getText().trim().isEmpty()) {
+      return new ValidationInfo("Working directory is empty", myProjectPathField);
+    }
+
+    return null;
+  }
+
+  @NotNull
+  public String getCommandLine() {
+    if (commandLineComboBox != null) {
+      return (String)commandLineComboBox.getEditor().getItem();
+    }
+    else {
+      return commandLineEditor.getText();
+    }
+  }
+
+  public void setCommandLine(@NotNull String fullCommandLine) {
+    if (commandLineComboBox != null) {
+      commandLineComboBox.setSelectedItem(fullCommandLine);
+    }
+
+    commandLineEditor.setText(fullCommandLine);
+  }
+
+  @NotNull
+  public String getWorkDirectory() {
+    return myProjectPathField.getText();
+  }
+
+  public void setWorkDirectory(@NotNull String path) {
+    myProjectPathField.setText(path);
+  }
+
+  protected JComponent createCenterPanel() {
+    return contentPane;
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return commandLineComboBox;
+  }
+}
index 231a57e4db1595a15fd26bbebab418066a753520..26853b81844ce67fba26b5d1f153b27237398512 100644 (file)
         <SOURCES />
       </library>
     </orderEntry>
+    <orderEntry type="module" module-name="external-system-impl" />
   </component>
   <component name="copyright">
     <Base>
       <setting name="state" value="1" />
     </Base>
   </component>
-</module>
-
+</module>
\ No newline at end of file
index 203d797518008c733ab49dfc25b2f2ccfad12eac..599a6198c61915cc96fd79c4a658b4911c2ce168 100644 (file)
@@ -2,11 +2,11 @@ package org.jetbrains.idea.maven.execution;
 
 import com.intellij.codeInsight.completion.CompletionResultSet;
 import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.externalSystem.service.execution.cmd.CommandLineCompletionProvider;
 import com.intellij.openapi.project.Project;
 import groovyjarjarcommonscli.OptionBuilder;
 import groovyjarjarcommonscli.Options;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.idea.maven.execution.cmd.CommandLineCompletionProvider;
 import org.jetbrains.idea.maven.project.MavenProjectsManager;
 import org.jetbrains.idea.maven.utils.MavenUtil;
 
index 99f61d6cfcc59fd81e321f477329feeae93c829f..a74041bbe1584e5dc8e3b50f368c8e9f6d460fe7 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet;
 import com.intellij.codeInsight.lookup.LookupElementBuilder;
 import com.intellij.execution.configurations.ParametersList;
 import com.intellij.icons.AllIcons;
+import com.intellij.openapi.externalSystem.service.execution.cmd.ParametersListLexer;
 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.FixedSizeButton;
@@ -31,7 +32,6 @@ import com.intellij.ui.components.JBLabel;
 import com.intellij.util.TextFieldCompletionProvider;
 import com.intellij.util.execution.ParametersListUtil;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.idea.maven.execution.cmd.ParametersListLexer;
 import org.jetbrains.idea.maven.model.MavenConstants;
 import org.jetbrains.idea.maven.project.MavenProjectsManager;
 
index 34cddb63a30cc820e6817188a3b1c075a5f2fd7d..48977fab92333564a48874e8120525382327f957 100644 (file)
@@ -17,14 +17,12 @@ package org.jetbrains.idea.maven.utils.actions;
 
 import com.intellij.openapi.actionSystem.CommonDataKeys;
 import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.DataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.externalSystem.action.ExternalSystemActionUtil;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ProjectFileIndex;
 import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.idea.maven.model.MavenConstants;
 import org.jetbrains.idea.maven.project.MavenProject;
@@ -63,7 +61,7 @@ public class MavenActionUtil {
       if (result != null) return result;
     }
 
-    Module module = getModule(context);
+    Module module = ExternalSystemActionUtil.getModule(context);
     if (module != null) {
       result = manager.findProject(module);
       if (result != null) return result;
@@ -72,12 +70,6 @@ public class MavenActionUtil {
     return null;
   }
 
-  @Nullable
-  private static Module getModule(DataContext context) {
-    final Module module = DataKeys.MODULE.getData(context);
-    return module != null ? module : DataKeys.MODULE_CONTEXT.getData(context);
-  }
-
   @Nullable
   public static MavenProjectsManager getProjectsManager(DataContext context) {
     final Project project = getProject(context);