All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.mvc.loco.view.ScriptPanel Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.mvc.loco.view;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.commons.lang3.StringUtils;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.api.script.ScriptCommand;
import org.bidib.wizard.api.script.ScriptEngineListener;
import org.bidib.wizard.api.script.ScriptStatus;
import org.bidib.wizard.client.common.text.WizardComponentFactory;
import org.bidib.wizard.common.model.settings.WizardSettingsInterface;
import org.bidib.wizard.common.script.DefaultScriptContext;
import org.bidib.wizard.common.script.engine.ScriptEngine;
import org.bidib.wizard.common.script.loco.LocoViewScripting;
import org.bidib.wizard.common.service.SettingsService;
import org.bidib.wizard.core.dialog.FileDialog;
import org.bidib.wizard.mvc.loco.view.listener.LocoViewListener;
import org.bidib.wizard.nodescript.script.loco.LocoScriptCommandFactory;
import org.bidib.wizard.nodescript.script.loco.StopEmergencyCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.FormBuilder;

public class ScriptPanel implements LocoViewListener, ScriptEngineListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(ScriptPanel.class);

    private static final String ENCODED_DIALOG_COLUMN_SPECS = "60dlu, 3dlu, 60dlu, 3dlu, 0dlu:grow";

    private static final String ENCODED_DIALOG_ROW_SPECS = "pref, 3dlu, pref, 3dlu, pref";

    // description, suffix for script files
    private static String scriptDescription;

    private static final String WORKING_DIR_LOCO_SCRIPT_KEY = "locoScript";

    private static final String SCRIPT_EXTENSION = "dcct";

    private static FileFilter scriptFilter;

    private ValueModel selectedScriptModel = new ValueHolder();

    private ValueModel currentCommandModel = new ValueHolder();

    private JButton startScript;

    private JButton stopScript;

    private LocoViewScripting scripting;

    private ScriptEngine scriptEngine;

    private ValueModel checkRepeatingModel = new ValueHolder();

    private AtomicBoolean scriptRepeating = new AtomicBoolean(false);

    private JPanel contentPanel;

    private final SettingsService settingsService;

    public ScriptPanel(final LocoViewScripting scripting, final SettingsService settingsService) {
        this.scripting = scripting;
        this.settingsService = settingsService;

        scriptDescription = Resources.getString(ScriptPanel.class, "scriptDescription");
        scriptFilter = new FileNameExtensionFilter(scriptDescription, SCRIPT_EXTENSION);
    }

    public JPanel createPanel() {

        // create the script engine
        scriptEngine = new ScriptEngine(scripting, new DefaultScriptContext());
        scriptEngine.addScriptEngineListener(this);

        checkRepeatingModel.setValue(scriptRepeating.get());

        final FormBuilder formBuilder =
            FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS);

        JButton selectScript = new JButton(Resources.getString(ScriptPanel.class, "selectScript"));
        selectScript.addActionListener(evt -> {

            final WizardSettingsInterface wizardSettings = settingsService.getWizardSettings();
            String storedWorkingDirectory = wizardSettings.getWorkingDirectory(WORKING_DIR_LOCO_SCRIPT_KEY);

            // select the script file
            FileDialog dialog =
                new FileDialog(contentPanel, FileDialog.OPEN, storedWorkingDirectory, "*." + SCRIPT_EXTENSION,
                    scriptFilter) {

                    @Override
                    public void approve(final String fileName) {
                        LOGGER.info("Load script: {}", fileName);
                        try {
                            File file = new File(fileName);
                            if (file.exists()) {
                                LOGGER.info("The script file exists: {}", file);
                                selectedScriptModel.setValue(file.getName());

                                prepareScript(fileName);

                                startScript.setEnabled(true);

                                final String workingDir = Paths.get(fileName).getParent().toString();
                                LOGGER.info("Save current workingDir: {}", workingDir);

                                wizardSettings.setWorkingDirectory(WORKING_DIR_LOCO_SCRIPT_KEY, workingDir);
                            }
                            else {
                                selectedScriptModel.setValue("no script selected");
                                startScript.setEnabled(false);
                            }
                        }
                        catch (IOException ex) {
                            LOGGER.info("Load and process script file failed.", ex);
                            startScript.setEnabled(false);
                        }
                        finally {
                        }
                    }
                };
            dialog.showDialog();
        });
        formBuilder.add(selectScript).xy(1, 1);

        JLabel scriptLabel = WizardComponentFactory.createLabel(selectedScriptModel);
        formBuilder.add(scriptLabel).xyw(3, 1, 3);

        JCheckBox repeatingCheck =
            WizardComponentFactory
                .createCheckBox(checkRepeatingModel, Resources.getString(ScriptPanel.class, "repeating"));
        // formBuilder.nextLine();
        formBuilder.add(repeatingCheck).xyw(1, 3, 3);

        // formBuilder.nextLine();

        startScript = new JButton(Resources.getString(ScriptPanel.class, "startScript"));
        startScript.setEnabled(false);
        startScript.addActionListener(evt -> scriptEngine.startScript());
        formBuilder.add(startScript).xy(1, 5);

        stopScript = new JButton(Resources.getString(ScriptPanel.class, "stopScript"));
        stopScript.setEnabled(false);
        stopScript.addActionListener(evt -> stopScript());
        formBuilder.add(stopScript).xy(3, 5);

        JLabel currentCommandLabel = WizardComponentFactory.createLabel(currentCommandModel);
        formBuilder.add(currentCommandLabel).xy(5, 5);

        checkRepeatingModel.addValueChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.info("Repeating has changed: {}", checkRepeatingModel.getValue());
                Boolean repeating = (Boolean) checkRepeatingModel.getValue();

                scriptRepeating.set(repeating);
                scriptEngine.setScriptRepeating(repeating);
            }
        });

        contentPanel = formBuilder.build();
        return contentPanel;
    }

    @Override
    public void currentCommandChanged(final ScriptCommand command) {

        if (SwingUtilities.isEventDispatchThread()) {
            currentCommandModel.setValue((command != null ? command.toString() : null));
        }
        else {
            try {
                SwingUtilities
                    .invokeAndWait(() -> currentCommandModel.setValue((command != null ? command.toString() : null)));
            }
            catch (InvocationTargetException | InterruptedException e) {
                LOGGER.warn("Update current command failed.", e);
            }
        }
    }

    private void stopScript() {
        LOGGER.info("Stop the script.");
        scriptEngine.stopScript();
    }

    @Override
    public void scriptStatusChanged(final ScriptStatus scriptStatus) {
        SwingUtilities.invokeLater(() -> {

            switch (scriptStatus) {
                case RUNNING:
                    startScript.setEnabled(false);
                    stopScript.setEnabled(true);
                    break;
                case ABORTED:
                case STOPPED:
                case FINISHED:
                case FINISHED_WITH_ERRORS:
                    startScript.setEnabled(true);
                    stopScript.setEnabled(false);
                    break;
                default:
                    break;
            }
            currentCommandChanged(null);
        });
    }

    @Override
    public void stop() {
        LOGGER.info("Stop was signalled.");

    }

    @Override
    public void emergencyStop() {
        LOGGER.info("EmergencyStop was signalled.");

        if (!StopEmergencyCommand.KEY.equals(currentCommandModel.getValue())) {
            LOGGER.info("EmergencyStop was triggered. Stop the script.");
            stopScript();
        }
    }

    private void prepareScript(String fileName) throws IOException {
        Path fFilePath = Paths.get(fileName);

        LocoScriptCommandFactory factory = new LocoScriptCommandFactory();
        factory.registerCommands();
        List> scriptCommands = new LinkedList>();

        try (Scanner scanner = new Scanner(fFilePath, StandardCharsets.UTF_8)) {
            while (scanner.hasNextLine()) {
                processLine(scanner.nextLine().trim(), factory, scriptCommands);
            }
        }

        LOGGER.info("Prepared list of commands: {}", scriptCommands);

        scriptEngine.setScriptCommands(scriptCommands);
    }

    private void processLine(
        String line, LocoScriptCommandFactory factory, List> scriptCommands) {
        LOGGER.info("Process line: {}", line);

        if (line.startsWith("#") || StringUtils.isBlank(line)) {
            LOGGER.info("Skip comment or empty line.");
        }
        else {
            LOGGER.info("Current line: {}", line);
            ScriptCommand command = factory.parse(line);
            if (command != null) {
                scriptCommands.add(command);
            }
        }
    }

    public void close() {

        if (scriptEngine != null) {
            LOGGER.info("Stop and release the scriptEngine.");

            scriptEngine.stopScript(1000L);

            scriptEngine.removeScriptEngineListener(this);

            scriptEngine = null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy