
org.bidib.wizard.mvc.loco.view.LocoView Maven / Gradle / Ivy
package org.bidib.wizard.mvc.loco.view;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.bidib.wizard.comm.Direction;
import org.bidib.wizard.comm.SpeedSteps;
import org.bidib.wizard.locale.Resources;
import org.bidib.wizard.mvc.common.view.ViewCloseListener;
import org.bidib.wizard.mvc.loco.model.LocoModel;
import org.bidib.wizard.mvc.loco.model.listener.LocoModelListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LocoView extends JDialog implements LocoViewScripting {
private static final Logger LOGGER = LoggerFactory.getLogger(LocoView.class);
private static final long serialVersionUID = 1L;
private LocoModel locoModel;
private final JComboBox speedStepsCombo;
private final JTextField address;
private final JSlider speedSlider;
private final JButton stopButton;
private final JButton stopEmergencyButton;
private Map functionButtonMap = new HashMap<>();
private final List locoViewListeners = new LinkedList();
private final List viewCloseListeners = new LinkedList();
private LocoModelListener locoModelListener;
private ScriptPanel scriptPanel;
public LocoView(JFrame parent, final LocoModel model, int x, int y) {
super(parent);
this.locoModel = model;
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new GridBagLayout());
setLocation(x, y);
setTitle(Resources.getString(getClass(), "title"));
JPanel infoPanel = new JPanel(new GridBagLayout());
infoPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "loco") + ":"));
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 5, 5, 5);
c.weightx = 0;
infoPanel.add(new JLabel(Resources.getString(getClass(), "address") + ":"), c);
address = new JFormattedTextField(NumberFormat.getNumberInstance());
address.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
valueChanged();
}
@Override
public void removeUpdate(DocumentEvent e) {
valueChanged();
}
@Override
public void insertUpdate(DocumentEvent e) {
valueChanged();
}
private void valueChanged() {
if (!address.getText().isEmpty()) {
if (locoModel != null) {
try {
locoModel.setAddress(Integer.parseInt(address.getText()));
}
catch (NumberFormatException e) {
LOGGER.warn("Parse decoder address failed.");
}
}
}
}
});
address.setText("3");
c.gridx++;
c.weightx = 1;
infoPanel.add(address, c);
c.gridx++;
c.weightx = 0;
infoPanel.add(new JLabel(Resources.getString(getClass(), "speedSteps") + ":"), c);
speedStepsCombo = new JComboBox(SpeedSteps.values());
speedStepsCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Speed steps combo has changed, update loco model.");
locoModel.setSpeedSteps((SpeedSteps) ((JComboBox) e.getSource()).getSelectedItem());
}
});
speedStepsCombo.setSelectedIndex(locoModel.getSpeedSteps().ordinal());
c.gridx++;
infoPanel.add(speedStepsCombo, c);
c.gridwidth = 3;
c.gridx = 0;
c.weightx = 1;
add(infoPanel, c);
JPanel directionPanel = new JPanel(new GridBagLayout());
directionPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "speed") + ":"));
speedSlider = new JSlider(JSlider.HORIZONTAL);
speedSlider.setMaximum(locoModel.getSpeedSteps().getSteps());
speedSlider.setMinimum(-locoModel.getSpeedSteps().getSteps());
speedSlider.setMajorTickSpacing(speedSlider.getMaximum());
speedSlider.setPaintTicks(true);
speedSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (!speedSlider.getValueIsAdjusting()) {
int value = (int) speedSlider.getValue();
if (value > 0) {
locoModel.setDirection(Direction.FORWARD);
value++;
}
else if (value < 0) {
locoModel.setDirection(Direction.BACKWARD);
value--;
}
value = Math.abs(value);
LOGGER.debug("Set the speed value: {}", value);
locoModel.setSpeed(value);
}
}
});
// this stops the loco ...
speedSlider.setValue(0);
c.gridx = 0;
c.weightx = 1;
directionPanel.add(speedSlider, c);
c.fill = GridBagConstraints.NONE;
c.gridwidth = 1;
c.gridy++;
directionPanel.add(new JLabel(Resources.getString(getClass(), "backwards")), c);
final JLabel reportedSpeed = new JLabel(String.valueOf(locoModel.getCurrentSpeed()));
c.anchor = GridBagConstraints.CENTER;
c.gridx++;
directionPanel.add(reportedSpeed, c);
c.anchor = GridBagConstraints.FIRST_LINE_END;
c.gridx++;
directionPanel.add(new JLabel(Resources.getString(getClass(), "forwards")), c);
c.anchor = GridBagConstraints.CENTER;
c.fill = GridBagConstraints.NONE;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridx = 0;
c.gridy++;
directionPanel.add(new JLabel(Resources.getString(getClass(), "reportedSpeed")), c);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 3;
c.gridx = 0;
c.gridy++;
add(directionPanel, c);
final List buttons = new LinkedList();
JPanel f0ButtonPanel = new JPanel(new GridBagLayout());
f0ButtonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "light") + ":"));
final JToggleButton f0Button = new JToggleButton("*");
f0Button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
locoModel.setFunction(0, f0Button.isSelected());
}
});
buttons.add(f0Button);
functionButtonMap.put("F0", f0Button);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 1;
c.gridy++;
c.weighty = 1;
f0ButtonPanel.add(f0Button, c);
c.weightx = 0.1;
add(f0ButtonPanel, c);
JPanel stopPanel = new JPanel(new GridBagLayout());
stopPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "stopLoco") + ":"));
stopButton = new JButton(Resources.getString(getClass(), "stop"));
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireStop();
}
});
c.weightx = 0.5;
stopPanel.add(stopButton, c);
stopEmergencyButton = new JButton(Resources.getString(getClass(), "emergencyStop"));
stopEmergencyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireEmergencyStop();
}
});
c.gridx++;
stopPanel.add(stopEmergencyButton, c);
c.anchor = GridBagConstraints.FIRST_LINE_END;
c.gridx = 2;
c.weightx = 0.9;
add(stopPanel, c);
JPanel functionPanel = new JPanel(new GridBagLayout());
functionPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "additionalFunctions") + ":"));
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 1;
c.weightx = 1;
for (int row = 0; row < 4; row++) {
c.gridx = 0;
c.gridy++;
for (int column = 0; column < 7; column++) {
final int functionIndex = row * 7 + (column + 1);
final String buttonText = "F" + functionIndex;
final JToggleButton functionButton = new JToggleButton(buttonText);
functionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Set function with index: {}", functionIndex);
locoModel.setFunction(functionIndex, functionButton.isSelected());
}
});
buttons.add(functionButton);
functionButtonMap.put(buttonText, functionButton);
functionPanel.add(functionButton, c);
c.gridx++;
}
}
c.gridwidth = 3;
c.gridx = 0;
c.gridy++;
add(functionPanel, c);
// prepare the script panel
scriptPanel = new ScriptPanel(this);
addLocoViewListener(scriptPanel);
JPanel panel = scriptPanel.createPanel();
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "script") + ":"));
c.gridwidth = 3;
c.gridx = 0;
c.gridy++;
add(panel, c);
// add loco model listener
locoModelListener = new LocoModelListener() {
@Override
public void addressChanged(int address) {
reportedSpeed.setText("");
}
@Override
public void currentSpeedChanged(int currentSpeed) {
reportedSpeed.setText(String.valueOf(currentSpeed));
}
@Override
public void directionChanged(Direction direction) {
}
@Override
public void functionChanged(int index, boolean value) {
buttons.get(index).setSelected(value);
}
@Override
public void speedChanged(int speed) {
if (speed == 0 || speed == 1) {
speedSlider.setValue(0);
}
}
@Override
public void speedStepsChanged(SpeedSteps speedSteps) {
speedSlider.setMaximum(speedSteps.getSteps());
speedSlider.setMinimum(-speedSteps.getSteps());
speedSlider.setMajorTickSpacing(speedSlider.getMaximum());
}
};
locoModel.addLocoModelListener(locoModelListener);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
LOGGER.info("The window is closing: {}", e.getWindow());
cleanup();
super.windowClosing(e);
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
LOGGER.info("The window is closed: {}", e.getWindow());
super.windowClosed(e);
}
});
pack();
setMinimumSize(getSize());
setVisible(true);
}
private void addLocoViewListener(LocoViewListener listener) {
locoViewListeners.add(listener);
}
public void addViewCloseListener(ViewCloseListener listener) {
viewCloseListeners.add(listener);
}
private void fireEmergencyStop() {
locoModel.setSpeed(1);
for (LocoViewListener listener : locoViewListeners) {
listener.emergencyStop();
}
}
private void fireStop() {
locoModel.setSpeed(0);
for (LocoViewListener listener : locoViewListeners) {
listener.stop();
}
}
@Override
public void selectDecoderAddress(int dccAddress) {
LOGGER.info("Select the decoder address: {}", dccAddress);
address.setText(String.valueOf(dccAddress));
}
@Override
public void setSpeedSteps(SpeedSteps speedSteps) {
LOGGER.info("Set the speed steps: {}", speedSteps);
speedStepsCombo.setSelectedItem(speedSteps);
}
@Override
public void setSpeed(int speed) {
LOGGER.info("Set the speed: {}", speed);
speedSlider.setValue(speed);
}
@Override
public void setFunction(int function) {
LOGGER.info("Set the function: {}", function);
JToggleButton functionButton = functionButtonMap.get("F" + function);
LOGGER.warn("Fetched functionButton: {}", functionButton);
functionButton.doClick();
}
@Override
public void setStop() {
LOGGER.info("Set stop.");
stopButton.doClick();
}
@Override
public void setStopEmergency() {
LOGGER.info("Set stop emergency.");
stopEmergencyButton.doClick();
}
public void close() {
LOGGER.info("The LocoView should be closed.");
cleanup();
LOGGER.info("Cleanup has passed, set visible false.");
setVisible(false);
}
private void cleanup() {
LOGGER.info("The LocoView is disposed.");
for (ViewCloseListener closeListener : viewCloseListeners) {
try {
closeListener.close();
}
catch (Exception ex) {
LOGGER.warn("Notify view close listener failed.", ex);
}
}
viewCloseListeners.clear();
locoViewListeners.clear();
if (locoModelListener != null) {
locoModel.removeLocoModelListener(locoModelListener);
locoModelListener = null;
}
if (scriptPanel != null) {
scriptPanel.close();
scriptPanel = null;
}
if (locoModel != null) {
locoModel = null;
}
functionButtonMap.clear();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy