content: package com.antfortune.freeline.idea.views;
  
  import com.intellij.openapi.actionSystem.ActionManager;
  import com.intellij.openapi.actionSystem.ActionToolbar;
  import com.intellij.openapi.actionSystem.AnActionEvent;
  import com.intellij.openapi.actionSystem.DefaultActionGroup;
  import com.intellij.openapi.components.ProjectComponent;
  import com.intellij.openapi.project.DumbAwareAction;
  import com.intellij.openapi.project.Project;
  import com.intellij.openapi.ui.SimpleToolWindowPanel;
  import com.intellij.openapi.wm.ToolWindow;
  import com.intellij.openapi.wm.ToolWindowManager;
  import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
  import com.intellij.openapi.wm.ex.ToolWindowManagerListener;
  import com.intellij.ui.content.Content;
  import com.intellij.ui.content.ContentFactory;
  import com.jediterm.terminal.Terminal;
  import com.jediterm.terminal.model.TerminalTextBuffer;
  import com.jediterm.terminal.ui.JediTermWidget;
  import com.antfortune.freeline.idea.icons.PluginIcons;
  import org.jetbrains.annotations.NotNull;
  import org.jetbrains.annotations.Nullable;
  import org.jetbrains.plugins.terminal.AbstractTerminalRunner;
  import org.jetbrains.plugins.terminal.JBTabbedTerminalWidget;
  import org.jetbrains.plugins.terminal.LocalTerminalDirectRunner;
  import com.antfortune.freeline.idea.utils.*;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.FocusEvent;
  import java.awt.event.FocusListener;
  import java.awt.event.KeyEvent;
  import java.util.*;
  import java.util.List;
  
  /**
   * Created by pengwei on 16/9/15.
   */
  public class FreelineTerminal implements FocusListener, ProjectComponent {
  
      private JBTabbedTerminalWidget myTerminalWidget;
      private Project myProject;
  
      public FreelineTerminal(Project project) {
          this.myProject = project;
      }
  
      public static FreelineTerminal getInstance(Project project) {
          return project.getComponent(FreelineTerminal.class);
      }
  
      public JBTabbedTerminalWidget getTerminalWidget(ToolWindow window) {
          window.show(null);
          if (myTerminalWidget == null) {
              JComponent parentPanel =  window.getContentManager().getContents()[0].getComponent();
              if (parentPanel instanceof SimpleToolWindowPanel) {
                  SimpleToolWindowPanel panel = (SimpleToolWindowPanel) parentPanel;
                  JPanel jPanel = (JPanel) panel.getComponents()[0];
                  myTerminalWidget = (JBTabbedTerminalWidget) jPanel.getComponents()[0];
              } else {
                  NotificationUtils.infoNotification("Wait for Freeline to initialize");
              }
          }
          return myTerminalWidget;
      }
  
      public JBTabbedTerminalWidget getTerminalWidget() {
          ToolWindow window = getToolWindow();
          return getTerminalWidget(window);
      }
  
      public JediTermWidget getCurrentSession() {
          if (getTerminalWidget() != null) {
              return getTerminalWidget().getCurrentSession();
          }
          return null;
      }
  
      /**
       * 在terminal输入shell
       */
      private void sendString(String shell) {
          if (getCurrentSession() != null) {
              getCurrentSession().getTerminalStarter().sendString(shell);
          }
      }
  
      public void initAndExecute(final String[] shell) {
          ToolWindow toolWindow = getToolWindow();
          if (toolWindow.isActive()) {
              executeShell(shell);
          } else {
              toolWindow.activate(new Runnable() {
                  @Override
                  public void run() {
                      executeShell(shell);
                  }
              });
          }
      }
  
      /**
       * 执行shell
       * 利用terminal换行即执行原理
       *
       * @param shell
       */
      public void executeShell(String shell) {
          if (getCurrentSession() != null) {
              TerminalTextBuffer buffer = getTerminalWidget().getCurrentSession().getTerminalTextBuffer();
              String lastLineText = buffer.getLine(buffer.getScreenLinesCount() - 1).getText().trim();
              shell = shell + " " + Utils.BREAK_LINE;
              if (!lastLineText.endsWith("$") && lastLineText.trim().length() != 0) {
                  shell = "#" + Utils.BREAK_LINE + shell;
              }
              sendString(shell);
          }
      }
  
      /**
       * 执行shell
       *
       * @param shell
       */
      public void executeShell(String[] shell) {
          StringBuilder build = new StringBuilder();
          if (shell != null && shell.length > 0) {
          for (String s : shell) {
              if (s == null) {
                  continue;
              }
              build.append(s + " ");
          }
      }
      executeShell(build.toString());
  }
  
      public void initTerminal(final ToolWindow toolWindow) {
          toolWindow.setToHideOnEmptyContent(true);
          LocalTerminalDirectRunner terminalRunner = LocalTerminalDirectRunner.createTerminalRunner(myProject);
          toolWindow.setStripeTitle("Freeline");
          Content content = createTerminalInContentPanel(terminalRunner, toolWindow);
          toolWindow.getContentManager().addContent(content);
          toolWindow.setShowStripeButton(true);
          toolWindow.setTitle("Console");
          ((ToolWindowManagerEx) ToolWindowManager.getInstance(this.myProject)).addToolWindowManagerListener(new ToolWindowManagerListener() {
              @Override
              public void toolWindowRegistered(@NotNull String s) {
  
              }
  
              @Override
              public void stateChanged() {
                  ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(FreelineToolWindowFactory.TOOL_WINDOW_ID);
                  if (window != null) {
                      boolean visible = window.isVisible();
                      if (visible && toolWindow.getContentManager().getContentCount() == 0) {
                          initTerminal(window);
                      }
                  }
              }
          });
          toolWindow.show(null);
          JBTabbedTerminalWidget terminalWidget = getTerminalWidget(toolWindow);
          if (terminalWidget != null && terminalWidget.getCurrentSession() != null) {
              Terminal terminal = terminalWidget.getCurrentSession().getTerminal();
              if (terminal != null) {
                  terminal.setCursorVisible(false);
              }
          }
      }
  
      private ToolWindow getToolWindow() {
          return ToolWindowManager.getInstance(myProject).getToolWindow(FreelineToolWindowFactory.TOOL_WINDOW_ID);
      }
  
      /**
       * 创建Terminal panel
       *
       * @param terminalRunner
       * @param toolWindow
       * @return
       */
      private Content createTerminalInContentPanel(@NotNull AbstractTerminalRunner terminalRunner, @NotNull final ToolWindow toolWindow) {
          SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true);
          Content content = ContentFactory.SERVICE.getInstance().createContent(panel, "", false);
          content.setCloseable(true);
          myTerminalWidget = terminalRunner.createTerminalWidget(content);
          panel.setContent(myTerminalWidget.getComponent());
          panel.addFocusListener(this);
          ActionToolbar toolbar = createToolbar(terminalRunner, myTerminalWidget, toolWindow);
          toolbar.setTargetComponent(panel);
          panel.setToolbar(toolbar.getComponent());
          content.setPreferredFocusableComponent(myTerminalWidget.getComponent());
          return content;
      }
  
      /**
       * 创建左侧工具栏
       *
       * @param terminalRunner
       * @param terminal
       * @param toolWindow
       * @return
       */
      private ActionToolbar createToolbar(@Nullable AbstractTerminalRunner terminalRunner, @NotNull JBTabbedTerminalWidget terminal, @NotNull ToolWindow toolWindow) {
          DefaultActionGroup group = new DefaultActionGroup();
          if (terminalRunner != null) {
              group.add(new RunAction(this));
              group.add(new StopAction(this));
              group.addSeparator();
              group.add(new DebugAction(this));
              group.add(new ForceAction(this));
              group.addSeparator();
              group.add(new ClearAction(this));
          }
          return ActionManager.getInstance().createActionToolbar("unknown", group, false);
      }
  
      @Override
      public void focusGained(FocusEvent e) {
          JComponent component = myTerminalWidget != null ? myTerminalWidget.getComponent() : null;
          if (component != null) {
              component.requestFocusInWindow();
          }
      }
  
      @Override
      public void focusLost(FocusEvent e) {
  
      }
  
      @Override
      public void projectOpened() {
  
      }
  
      @Override
      public void projectClosed() {
  
      }
  
      @Override
      public void initComponent() {
  
      }
  
      @Override
      public void disposeComponent() {
  
      }
  
      @NotNull
      @Override
      public String getComponentName() {
          return "FreelineTerminal";
      }
  
      /**
       * 停止执行
       */
      private static class StopAction extends BaseTerminalAction {
          private Robot robot;
          public StopAction(FreelineTerminal terminal) {
              super(terminal, "Stop Run Freeline", "Stop Run Freeline", PluginIcons.Suspend);
              try {
                  robot = new Robot();
              } catch (AWTException e) {
                  e.printStackTrace();
              }
          }
  
          @Override
          public void doAction(AnActionEvent anActionEvent) {
              if (terminal.getCurrentSession() != null) {
                  terminal.getCurrentSession().getComponent().requestFocusInWindow();
                  Utils.keyPressWithCtrl(robot, KeyEvent.VK_C);
              }
          }
      }
  
      private static class RunAction extends BaseTerminalAction {
          String pythonLocation;
          public RunAction(FreelineTerminal terminal) {
              this(terminal, "Run Freeline", "Run Freeline", PluginIcons.FreelineIcon);
          }
  
          public RunAction(FreelineTerminal terminal, String text, String description, Icon icon) {
              super(terminal, text, description, icon);
          }
  
          @Override
          public void doAction(AnActionEvent anActionEvent) {
              pythonLocation = Utils.getPythonLocation();
              if (pythonLocation == null) {
                  NotificationUtils.pythonNotFound();
              } else {
                  terminal.executeShell(getArgs());
              }
          }
  
          private String[] getArgs() {
              List<String> args = new ArrayList<String>();
              args.add(pythonLocation);
              args.add("freeline.py");
              if (args() != null) {
                  args.add(args());
              }
              return args.toArray(new String[]{});
          }
  
          protected String args() {
              return null;
          }
      }
  
      private static class DebugAction extends RunAction {
          public DebugAction(FreelineTerminal terminal) {
              super(terminal, "Run Freeline -d", "Run Freeline -d", PluginIcons.StartDebugger);
          }
  
          @Override
          protected String args() {
              return "-d";
          }
      }
  
      private static class ForceAction extends RunAction {
          public ForceAction(FreelineTerminal terminal) {
              super(terminal, "Run Freeline -f", "Run Freeline -f", PluginIcons.QuickfixBulb);
          }
  
          @Override
          protected String args() {
              return "-f";
          }
      }
  
      /**
       * 清空terminal
       */
      private static class ClearAction extends BaseTerminalAction {
          public ClearAction(FreelineTerminal terminal) {
              super(terminal, "Clear", "Clear", PluginIcons.GC);
          }
  
          @Override
          public void doAction(AnActionEvent anActionEvent) {
              if (terminal.getCurrentSession() != null) {
                  terminal.getCurrentSession().getTerminal().reset();
                  terminal.getCurrentSession().getTerminal().setCursorVisible(false);
              }
          }
      }
  
      private static abstract class BaseTerminalAction extends DumbAwareAction {
          protected FreelineTerminal terminal;
  
          public BaseTerminalAction(FreelineTerminal terminal, String text, String description, Icon icon) {
              super(text, description, icon);
              this.terminal = terminal;
          }
  
          @Override
          public void actionPerformed(AnActionEvent anActionEvent) {
              DocumentUtil.saveDocument();
              if (FreelineUtil.checkInstall(anActionEvent.getProject())) {
                  doAction(anActionEvent);
              }
          }
  
          public abstract void doAction(AnActionEvent anActionEvent);
      }
  }
  