org.bidib.wizard.mvc.loco.view.ScriptPanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-client Show documentation
Show all versions of bidibwizard-client Show documentation
jBiDiB BiDiB Wizard Client Application POM
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;
}
}
}