Exit Full View

ToolApp / TerminalFX / src / main / java / com / kodedu / terminalfx / TerminalTab.java

package com.kodedu.terminalfx;

import com.kodedu.terminalfx.config.TabNameGenerator;
import com.kodedu.terminalfx.config.TerminalConfig;
import com.kodedu.terminalfx.helper.IOHelper;
import com.kodedu.terminalfx.helper.ThreadHelper;
import com.pty4j.PtyProcess;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.input.KeyEvent;

import java.io.Reader;
import java.io.Writer;
import java.nio.file.Path;
import java.util.Objects;

public class TerminalTab extends Tab {

    private final Terminal terminal;
    private final TabNameGenerator tabNameGenerator;
    private static final String NEW_TAB_KEY = "T";

    public TerminalTab(TerminalConfig terminalConfig, TabNameGenerator tabNameGenerator, Path terminalPath) {
        this(new Terminal(terminalConfig, terminalPath), tabNameGenerator);
    }

    public TerminalTab(Terminal terminal, TabNameGenerator tabNameGenerator) {
        this.terminal = terminal;
        this.tabNameGenerator = tabNameGenerator;

        this.terminal.addEventFilter(KeyEvent.KEY_PRESSED, event -> {

            if (event.isShortcutDown() && NEW_TAB_KEY.equalsIgnoreCase(event.getText())) {
                newTerminal();
            }
        });

        this.setOnCloseRequest(event -> {
            event.consume();
            closeTerminal();
        });

        final String tabName = getTabNameGenerator().next();
        setText(tabName);

        final ContextMenu contextMenu = new ContextMenu();
        final MenuItem newTab = new MenuItem("New Tab");
        final MenuItem closeTab = new MenuItem("Close");
        final MenuItem closeOthers = new MenuItem("Close Others");
        final MenuItem closeAll = new MenuItem("Close All");

        newTab.setOnAction(this::newTerminal);
        closeTab.setOnAction(this::closeTerminal);
        closeAll.setOnAction(this::closeAllTerminal);
        closeOthers.setOnAction(this::closeOtherTerminals);

        contextMenu.getItems().addAll(newTab, closeTab, closeOthers, closeAll);
        this.setContextMenu(contextMenu);

        setContent(terminal);
    }

    private void closeOtherTerminals(ActionEvent actionEvent) {
        final ObservableList<Tab> tabs = FXCollections.observableArrayList(this.getTabPane().getTabs());
        for (final Tab tab : tabs) {
            if (tab instanceof TerminalTab) {
                if (tab != this) {
                    ((TerminalTab) tab).closeTerminal();
                }
            }
        }
    }

    private void closeAllTerminal(ActionEvent actionEvent) {
        final ObservableList<Tab> tabs = FXCollections.observableArrayList(this.getTabPane().getTabs());
        for (final Tab tab : tabs) {
            if (tab instanceof TerminalTab) {
                ((TerminalTab) tab).closeTerminal();
            }
        }
    }

    public void newTerminal(ActionEvent... actionEvent) {
        final TerminalTab terminalTab = new TerminalTab(getTerminalConfig(), getTabNameGenerator(), getTerminalPath());
        getTabPane().getTabs().add(terminalTab);
        getTabPane().getSelectionModel().select(terminalTab);
    }

    public void closeTerminal(ActionEvent... actionEvent) {
        ThreadHelper.runActionLater(() -> {
            final ObservableList<Tab> tabs = this.getTabPane().getTabs();
            if (tabs.size() == 1) {
                newTerminal(actionEvent);
            }
            tabs.remove(this);

            destroy();
        });
    }

    public void destroy() {
        ThreadHelper.start(() -> {
            while (Objects.isNull(getProcess())) {
                ThreadHelper.sleep(250);
            }
            getProcess().destroy();
            IOHelper.close(getInputReader(), getErrorReader(), getOutputWriter());
        });
    }

    public void onTerminalFxReady(Runnable onReadyAction) {
        terminal.onTerminalFxReady(onReadyAction);
    }

    public TabNameGenerator getTabNameGenerator() {
        return tabNameGenerator;
    }

    public Path getTerminalPath() {
        return terminal.getTerminalPath();
    }

    public TerminalConfig getTerminalConfig() {
        return terminal.getTerminalConfig();
    }

    public PtyProcess getProcess() {
        return terminal.getProcess();
    }

    public Reader getInputReader() {
        return terminal.getInputReader();
    }

    public Reader getErrorReader() {
        return terminal.getErrorReader();
    }

    public Writer getOutputWriter() {
        return terminal.getOutputWriter();
    }

    public Terminal getTerminal() {
        return terminal;
    }
}