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);
}
}