package com.jediterm.terminal.ui;
import com.google.common.collect.Lists;
import com.jediterm.terminal.Terminal;
import com.jediterm.terminal.TerminalDisplay;
import com.jediterm.terminal.TerminalStarter;
import com.jediterm.terminal.TtyConnector;
import com.jediterm.terminal.debug.DebugBufferType;
import com.jediterm.terminal.display.BackBuffer;
import com.jediterm.terminal.display.JediTerminal;
import com.jediterm.terminal.display.StyleState;
import com.jediterm.terminal.ui.settings.SettingsProvider;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* JediTerm terminal widget with UI implemented in Swing.
* <p/>
*/
public class JediTermWidget extends JPanel implements TerminalSession, TerminalWidget, TerminalActionProvider {
private static final Logger LOG = Logger.getLogger(JediTermWidget.class);
protected final TerminalPanel myTerminalPanel;
protected final JediTerminal myTerminal;
protected final AtomicBoolean mySessionRunning = new AtomicBoolean();
protected PreConnectHandler myPreConnectHandler;
private TtyConnector myTtyConnector;
private TerminalStarter myTerminalStarter;
private Thread myEmuThread;
private final SettingsProvider mySettingsProvider;
private TerminalActionProvider myNextActionProvider;
public JediTermWidget(@NotNull SettingsProvider settingsProvider) {
this(80, 24, settingsProvider);
}
public JediTermWidget(Dimension dimension, SettingsProvider settingsProvider) {
this(dimension.width, dimension.height, settingsProvider);
}
public JediTermWidget(int columns, int lines, SettingsProvider settingsProvider) {
super(new BorderLayout());
mySettingsProvider = settingsProvider;
StyleState styleState = createDefaultStyle();
BackBuffer backBuffer = new BackBuffer(columns, lines, styleState);
myTerminalPanel = createTerminalPanel(mySettingsProvider, styleState, backBuffer);
myTerminal = new JediTerminal(myTerminalPanel, backBuffer, styleState);
myTerminalPanel.addTerminalMouseListener(myTerminal);
myTerminalPanel.setNextProvider(this);
myPreConnectHandler = createPreConnectHandler(myTerminal);
myTerminalPanel.setKeyListener(myPreConnectHandler);
JScrollBar scrollBar = createScrollBar();
add(myTerminalPanel, BorderLayout.CENTER);
add(scrollBar, BorderLayout.EAST);
scrollBar.setModel(myTerminalPanel.getBoundedRangeModel());
mySessionRunning.set(false);
myTerminalPanel.init();
myTerminalPanel.setVisible(true);
}
protected JScrollBar createScrollBar() {
return new JScrollBar();
}
protected StyleState createDefaultStyle() {
StyleState styleState = new StyleState();
styleState.setDefaultStyle(mySettingsProvider.getDefaultStyle());
return styleState;
}
protected TerminalPanel createTerminalPanel(SettingsProvider settingsProvider, StyleState styleState, BackBuffer backBuffer) {
return new TerminalPanel(settingsProvider, backBuffer, styleState);
}
protected PreConnectHandler createPreConnectHandler(JediTerminal terminal) {
return new PreConnectHandler(terminal);
}
public TerminalDisplay getTerminalDisplay() {
return getTerminalPanel();
}
public TerminalPanel getTerminalPanel() {
return myTerminalPanel;
}
public void setTtyConnector(@NotNull TtyConnector ttyConnector) {
myTtyConnector = ttyConnector;
myTerminalStarter = createTerminalStarter(myTerminal, myTtyConnector);
myTerminalPanel.setTerminalStarter(myTerminalStarter);
}
protected TerminalStarter createTerminalStarter(JediTerminal terminal, TtyConnector connector) {
return new TerminalStarter(terminal, connector);
}
@Override
public TtyConnector getTtyConnector() {
return myTtyConnector;
}
@Override
public Terminal getTerminal() {
return myTerminal;
}
@Override
public String getSessionName() {
if (myTtyConnector != null) {
return myTtyConnector.getName();
} else {
return "Session";
}
}
@Override
public void redraw() {
myTerminalPanel.redraw();
}
public void start() {
if (!mySessionRunning.get()) {
myEmuThread = new Thread(new EmulatorTask());
myEmuThread.start();
} else {
LOG.error("Should not try to start session again at this point... ");
}
}
public void stop() {
if (mySessionRunning.get() && myEmuThread != null) {
myEmuThread.interrupt();
}
}
public boolean isSessionRunning() {
return mySessionRunning.get();
}
public String getBufferText(DebugBufferType type) {
return type.getValue(this);
}
@Override
public BackBuffer getBackBuffer() {
return myTerminalPanel.getBackBuffer();
}
@Override
public boolean requestFocusInWindow() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myTerminalPanel.requestFocusInWindow();
}
});
return super.requestFocusInWindow();
}
public boolean canOpenSession() {
return !isSessionRunning();
}
@Override
public void setTerminalPanelListener(TerminalPanelListener terminalPanelListener) {
myTerminalPanel.setTerminalPanelListener(terminalPanelListener);
}
@Override
public TerminalSession getCurrentSession() {
return this;
}
@Override
public TerminalSession createTerminalSession(TtyConnector ttyConnector) {
setTtyConnector(ttyConnector);
return this;
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public void close() {
myTerminalStarter.close();
}
@Override
public List<TerminalAction> getActions() {
return Lists.newArrayList();
}
@Override
public TerminalActionProvider getNextProvider() {
return myNextActionProvider;
}
public void setNextProvider(TerminalActionProvider actionProvider) {
this.myNextActionProvider = actionProvider;
}
class EmulatorTask implements Runnable {
public void run() {
try {
mySessionRunning.set(true);
Thread.currentThread().setName("Connector-" + myTtyConnector.getName());
if (myTtyConnector.init(myPreConnectHandler)) {
myTerminalPanel.initKeyHandler();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myTerminalPanel.requestFocusInWindow();
}
});
myTerminalStarter.start();
}
} catch (Exception e) {
LOG.error("Exception running terminal", e);
} finally {
try {
myTtyConnector.close();
} catch (Exception e) {
}
mySessionRunning.set(false);
myTerminalPanel.setKeyListener(myPreConnectHandler);
}
}
}
public TerminalStarter getTerminalStarter() {
return myTerminalStarter;
}
}