Package com.jetbrains.lang.dart.ide.actions

Source Code of com.jetbrains.lang.dart.ide.actions.DartPubActionBase

package com.jetbrains.lang.dart.ide.actions;

import com.intellij.CommonBundle;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.actions.StopProcessAction;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.CloseActiveTabAction;
import com.intellij.ide.actions.ShowSettingsUtilImpl;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.UIBundle;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.MessageView;
import com.intellij.ui.content.tabs.PinToolwindowTabAction;
import com.jetbrains.lang.dart.DartBundle;
import com.jetbrains.lang.dart.DartProjectComponent;
import com.jetbrains.lang.dart.ide.runner.DartConsoleFilter;
import com.jetbrains.lang.dart.ide.runner.DartRelativePathsConsoleFilter;
import com.jetbrains.lang.dart.sdk.DartConfigurable;
import com.jetbrains.lang.dart.sdk.DartSdk;
import com.jetbrains.lang.dart.sdk.DartSdkUtil;
import icons.DartIcons;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.jetbrains.lang.dart.util.PubspecYamlUtil.PUBSPEC_YAML;

abstract public class DartPubActionBase extends AnAction implements DumbAware {
  private static final String GROUP_DISPLAY_ID = "Dart Pub Tool";
  private static final Key<PubToolWindowContentInfo> PUB_TOOL_WINDOW_CONTENT_INFO_KEY = Key.create("PUB_TOOL_WINDOW_CONTENT_INFO_KEY");

  private static final AtomicBoolean ourInProgress = new AtomicBoolean(false);

  public DartPubActionBase() {
    super(DartIcons.Dart_16);
  }

  @Override
  public void update(@NotNull final AnActionEvent e) {
    //e.getPresentation().setText(getTitle());  "Pub: Build..." action name set in plugin.xml is different from its "Pub: Build" title
    final boolean visible = getModuleAndPubspecYamlFile(e) != null;
    e.getPresentation().setVisible(visible);
    e.getPresentation().setEnabled(visible && !ourInProgress.get());
  }

  @Nullable
  private static Pair<Module, VirtualFile> getModuleAndPubspecYamlFile(final AnActionEvent e) {
    final Module module = LangDataKeys.MODULE.getData(e.getDataContext());
    final PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(e.getDataContext());

    if (module != null && psiFile != null && psiFile.getName().equalsIgnoreCase(PUBSPEC_YAML)) {
      final VirtualFile file = psiFile.getOriginalFile().getVirtualFile();
      return file != null ? Pair.create(module, file) : null;
    }
    return null;
  }

  @Nls
  protected abstract String getTitle();

  @Nullable
  protected abstract String[] calculatePubParameters(final Project project);

  @Override
  public void actionPerformed(@NotNull final AnActionEvent e) {
    final Pair<Module, VirtualFile> moduleAndPubspecYamlFile = getModuleAndPubspecYamlFile(e);
    if (moduleAndPubspecYamlFile == null) return;

    final Module module = moduleAndPubspecYamlFile.first;
    final VirtualFile pubspecYamlFile = moduleAndPubspecYamlFile.second;

    performPubAction(module, pubspecYamlFile, true);
  }

  public void performPubAction(final @NotNull Module module, final @NotNull VirtualFile pubspecYamlFile, final boolean allowModalDialogs) {
    DartSdk sdk = DartSdk.getGlobalDartSdk();

    if (sdk == null && allowModalDialogs) {
      final int answer = Messages.showDialog(module.getProject(),
                                             DartBundle.message("dart.sdk.is.not.configured"),
                                             getTitle(),
                                             new String[]{DartBundle.message("setup.dart.sdk"), CommonBundle.getCancelButtonText()},
                                             Messages.OK,
                                             Messages.getErrorIcon());
      if (answer != Messages.OK) return;

      ShowSettingsUtilImpl.showSettingsDialog(module.getProject(), DartConfigurable.DART_SETTINGS_PAGE_ID, "");
      sdk = DartSdk.getGlobalDartSdk();
    }

    if (sdk == null) return;

    File pubFile = new File(DartSdkUtil.getPubPath(sdk));
    if (!pubFile.isFile() && allowModalDialogs) {
      final int answer =
        Messages.showDialog(module.getProject(),
                            DartBundle.message("dart.sdk.bad.dartpub.path", pubFile.getPath()),
                            getTitle(),
                            new String[]{DartBundle.message("setup.dart.sdk"), CommonBundle.getCancelButtonText()},
                            Messages.OK,
                            Messages.getErrorIcon());
      if (answer != Messages.OK) return;

      ShowSettingsUtilImpl.showSettingsDialog(module.getProject(), DartConfigurable.DART_SETTINGS_PAGE_ID, "");

      sdk = DartSdk.getGlobalDartSdk();
      if (sdk == null) return;

      pubFile = new File(DartSdkUtil.getPubPath(sdk));
    }

    if (!pubFile.isFile()) return;

    final String[] pubParameters = calculatePubParameters(module.getProject());

    if (pubParameters != null) {
      final GeneralCommandLine command = new GeneralCommandLine().withWorkDirectory(pubspecYamlFile.getParent().getPath());
      command.setExePath(pubFile.getPath());
      command.addParameters(pubParameters);

      doPerformPubAction(module, pubspecYamlFile, command, getTitle());
    }
  }

  private static void doPerformPubAction(@NotNull final Module module,
                                         @NotNull final VirtualFile pubspecYamlFile,
                                         @NotNull final GeneralCommandLine command,
                                         @NotNull final String actionTitle) {
    FileDocumentManager.getInstance().saveAllDocuments();

    try {
      if (ourInProgress.compareAndSet(false, true)) {
        final OSProcessHandler processHandler = new OSProcessHandler(command);

        processHandler.addProcessListener(new ProcessAdapter() {
          @Override
          public void processTerminated(final ProcessEvent event) {
            ourInProgress.set(false);

            ApplicationManager.getApplication().invokeLater(new Runnable() {
              public void run() {
                DartProjectComponent.excludeBuildAndPackagesFolders(module, pubspecYamlFile);
                // refresh later than exclude, otherwise IDE may start indexing excluded folders
                pubspecYamlFile.getParent().refresh(true, true);
              }
            });
          }
        });

        showPubOutputConsole(module, command, processHandler, pubspecYamlFile, actionTitle);
      }
    }
    catch (ExecutionException e) {
      ourInProgress.set(false);

      // may be better show it in Messages tool window console?
      Notifications.Bus.notify(
        new Notification(GROUP_DISPLAY_ID, actionTitle, DartBundle.message("dart.pub.exception", e.getMessage()), NotificationType.ERROR));
    }
  }

  private static void showPubOutputConsole(@NotNull final Module module,
                                           @NotNull final GeneralCommandLine command,
                                           @NotNull final OSProcessHandler processHandler,
                                           @NotNull final VirtualFile pubspecYamlFile,
                                           @NotNull final String actionTitle) {
    final ConsoleView console;
    PubToolWindowContentInfo info = findExistingInfoForCommand(module.getProject(), command);

    if (info != null) {
      // rerunning the same pub command in the same tool window tab (corresponding tool window action invoked)
      console = info.console;
      console.clear();
    }
    else {
      console = createConsole(module.getProject(), pubspecYamlFile);
      info = new PubToolWindowContentInfo(module, pubspecYamlFile, command, actionTitle, console);

      final ActionToolbar actionToolbar = createToolWindowActionsBar(info);

      final SimpleToolWindowPanel toolWindowPanel = new SimpleToolWindowPanel(false, true);
      toolWindowPanel.setContent(console.getComponent());
      toolWindowPanel.setToolbar(actionToolbar.getComponent());

      final Content content = ContentFactory.SERVICE.getInstance().createContent(toolWindowPanel.getComponent(), actionTitle, true);
      content.putUserData(PUB_TOOL_WINDOW_CONTENT_INFO_KEY, info);
      Disposer.register(content, console);

      final ContentManager contentManager = MessageView.SERVICE.getInstance(module.getProject()).getContentManager();
      removeOldTabs(contentManager);
      contentManager.addContent(content);
      contentManager.setSelectedContent(content);

      final ToolWindow toolWindow = ToolWindowManager.getInstance(module.getProject()).getToolWindow(ToolWindowId.MESSAGES_WINDOW);
      toolWindow.activate(null, true);
    }

    info.rerunPubCommandAction.setProcessHandler(processHandler);
    info.stopProcessAction.setProcessHandler(processHandler);

    processHandler.addProcessListener(new ProcessAdapter() {
      @Override
      public void processTerminated(final ProcessEvent event) {
        console.print(IdeBundle.message("finished.with.exit.code.text.message", event.getExitCode()), ConsoleViewContentType.SYSTEM_OUTPUT);
      }
    });

    console.attachToProcess(processHandler);
    processHandler.startNotify();
  }

  @Nullable
  private static PubToolWindowContentInfo findExistingInfoForCommand(final Project project, @NotNull final GeneralCommandLine command) {
    for (Content content : MessageView.SERVICE.getInstance(project).getContentManager().getContents()) {
      final PubToolWindowContentInfo info = content.getUserData(PUB_TOOL_WINDOW_CONTENT_INFO_KEY);
      if (info != null && info.command == command) {
        return info;
      }
    }
    return null;
  }

  @NotNull
  private static ConsoleView createConsole(@NotNull final Project project, @NotNull final VirtualFile pubspecYamlFile) {
    final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
    consoleBuilder.setViewer(true);
    consoleBuilder.addFilter(new DartConsoleFilter(project, pubspecYamlFile));
    consoleBuilder.addFilter(new DartRelativePathsConsoleFilter(project, pubspecYamlFile.getParent().getPath()));
    return consoleBuilder.getConsole();
  }

  @NotNull
  private static ActionToolbar createToolWindowActionsBar(@NotNull final PubToolWindowContentInfo info) {
    final DefaultActionGroup actionGroup = new DefaultActionGroup();

    final RerunPubCommandAction rerunPubCommandAction = new RerunPubCommandAction(info);
    info.rerunPubCommandAction = rerunPubCommandAction;
    actionGroup.addAction(rerunPubCommandAction);

    final StopProcessAction stopProcessAction = new StopProcessAction(DartBundle.message("stop.pub.process.action"),
                                                                      DartBundle.message("stop.pub.process.action"),
                                                                      null);
    info.stopProcessAction = stopProcessAction;
    actionGroup.addAction(stopProcessAction);

    actionGroup.add(PinToolwindowTabAction.getPinAction());

    final AnAction closeContentAction = new CloseActiveTabAction();
    closeContentAction.getTemplatePresentation().setIcon(AllIcons.Actions.Cancel);
    closeContentAction.getTemplatePresentation().setText(UIBundle.message("tabbed.pane.close.tab.action.name"));
    actionGroup.add(closeContentAction);

    final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actionGroup, false);
    toolbar.setTargetComponent(info.console.getComponent());
    return toolbar;
  }

  private static void removeOldTabs(@NotNull final ContentManager contentManager) {
    for (Content content : contentManager.getContents()) {
      if (!content.isPinned() && content.isCloseable() && content.getUserData(PUB_TOOL_WINDOW_CONTENT_INFO_KEY) != null) {
        contentManager.removeContent(content, false);
      }
    }
  }

  private static class PubToolWindowContentInfo {
    private @NotNull final Module module;
    private @NotNull final VirtualFile pubspecYamlFile;
    private @NotNull final GeneralCommandLine command;
    private @NotNull final String actionTitle;
    private @NotNull final ConsoleView console;
    private RerunPubCommandAction rerunPubCommandAction;
    private StopProcessAction stopProcessAction;

    public PubToolWindowContentInfo(@NotNull final Module module,
                                    @NotNull final VirtualFile pubspecYamlFile,
                                    @NotNull final GeneralCommandLine command,
                                    @NotNull final String actionTitle,
                                    @NotNull final ConsoleView console) {
      this.module = module;
      this.pubspecYamlFile = pubspecYamlFile;
      this.command = command;
      this.actionTitle = actionTitle;
      this.console = console;
    }

    @Override
    public boolean equals(final Object o) {
      return o instanceof PubToolWindowContentInfo && command == ((PubToolWindowContentInfo)o).command;
    }

    @Override
    public int hashCode() {
      return command.hashCode();
    }
  }

  private static class RerunPubCommandAction extends AnAction {
    @NotNull private final PubToolWindowContentInfo myInfo;
    private OSProcessHandler myProcessHandler;

    public RerunPubCommandAction(@NotNull final PubToolWindowContentInfo info) {
      super(DartBundle.message("rerun.pub.command.action.name"),
            DartBundle.message("rerun.pub.command.action.description"),
            AllIcons.Actions.Execute);
      myInfo = info;

      registerCustomShortcutSet(CommonShortcuts.getRerun(), info.console.getComponent());
    }

    public void setProcessHandler(@NotNull final OSProcessHandler processHandler) {
      myProcessHandler = processHandler;
    }

    @Override
    public void update(@NotNull final AnActionEvent e) {
      e.getPresentation().setEnabled(!ourInProgress.get() && myProcessHandler != null && myProcessHandler.isProcessTerminated());
    }

    @Override
    public void actionPerformed(@NotNull final AnActionEvent e) {
      doPerformPubAction(myInfo.module, myInfo.pubspecYamlFile, myInfo.command, myInfo.actionTitle);
    }
  }
}
TOP

Related Classes of com.jetbrains.lang.dart.ide.actions.DartPubActionBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.