org.bidib.wizard.mvc.loco.view.LocoView 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.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicSliderUI;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.bidib.jbidibc.messages.enums.SpeedStepsEnum;
import org.bidib.jbidibc.messages.utils.ConversionUtils;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.client.common.beans.WizardPropertyConnector;
import org.bidib.wizard.client.common.binding.SwingPropertyAdapter;
import org.bidib.wizard.client.common.converter.BidibSpeedToDccSpeedConverter;
import org.bidib.wizard.client.common.converter.StringConverter;
import org.bidib.wizard.client.common.text.InputValidationDocument;
import org.bidib.wizard.client.common.text.IntegerRangeFilter;
import org.bidib.wizard.client.common.text.WizardComponentFactory;
import org.bidib.wizard.client.common.uils.SwingUtils;
import org.bidib.wizard.client.common.view.TabPanelProvider;
import org.bidib.wizard.client.common.view.slider.JZeroSlider;
import org.bidib.wizard.common.script.loco.LocoViewScripting;
import org.bidib.wizard.common.service.SettingsService;
import org.bidib.wizard.common.utils.ImageUtils;
import org.bidib.wizard.model.loco.LocoModel;
import org.bidib.wizard.model.loco.listener.LocoModelListener;
import org.bidib.wizard.model.locolist.LocoListModel;
import org.bidib.wizard.model.status.BinStateValue;
import org.bidib.wizard.model.status.DirectionStatus;
import org.bidib.wizard.model.status.RfBasisMode;
import org.bidib.wizard.model.status.SpeedSteps;
import org.bidib.wizard.mvc.common.view.ViewCloseListener;
import org.bidib.wizard.mvc.common.view.graph.LedBarGraph;
import org.bidib.wizard.mvc.common.view.graph.LedBarGraph.Orientation;
import org.bidib.wizard.mvc.common.view.panel.DisabledPanel;
import org.bidib.wizard.mvc.loco.controller.LocoControlListener;
import org.bidib.wizard.mvc.loco.model.LocoConfigModel;
import org.bidib.wizard.mvc.loco.view.listener.LocoViewListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jgoodies.binding.adapter.Bindings;
import com.jgoodies.binding.value.ConverterValueModel;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.FormsSetup;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.debug.FormDebugPanel;
import com.jgoodies.forms.factories.Paddings;
import com.jidesoft.swing.JideButton;
import com.jidesoft.swing.JideToggleButton;
import eu.hansolo.steelseries.gauges.Radial;
public class LocoView implements LocoViewScripting, TabPanelProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(LocoView.class);
private static final String ENCODED_DIALOG_COLUMN_SPECS = "pref, 3dlu, pref:grow";
private static final String ENCODED_DIALOG_ROW_SPECS = "pref, 3dlu, pref, 3dlu, pref, 9dlu, pref, 3dlu, pref";
private static final int PAGE_STEPS = 12;
private final LocoModel locoModel;
private final LocoConfigModel locoConfigModel;
private JComboBox speedStepsCombo;
private JTextField address;
private JLabel speed;
private JSlider speedSlider;
private JLabel reportedSpeed;
private JButton stopButton;
private JButton stopEmergencyButton;
private final Map functionButtonMap = new HashMap<>();
private final List locoViewListeners = new LinkedList();
private final List viewCloseListeners = new LinkedList();
private final LocoModelListener locoModelListener;
private JPanel directionPanel;
private JPanel lightAndStopButtonPanel;
private JPanel functionButtonPanel;
private JPanel multiRfBaseButtonPanel;
private JPanel counterPanel;
private JPanel directBinStatePanel;
private ScriptPanel scriptPanel;
private LedBarGraph ledBarGraph;
private JPanel contentPanel;
private boolean m4SupportEnabled;
// private JPanel imageOrVideoContainerPanel;
// private JPanel imagePanel;
private final Consumer locoAddressChangeListener;
private final LocoControlListener locoControlListener;
private final PropertyChangeListener locoModelPropertyChangeListener;
private final WizardPropertyConnector addressChangeConnector;
public LocoView(final LocoModel locoModel, final LocoConfigModel locoConfigModel,
final SettingsService settingsService, final LocoControlListener locoControlListener,
final Consumer locoAddressChangeListener) {
this.locoModel = locoModel;
this.locoConfigModel = locoConfigModel;
this.locoAddressChangeListener = locoAddressChangeListener;
this.locoControlListener = locoControlListener;
m4SupportEnabled = settingsService.getWizardSettings().isM4SupportEnabled();
// create form builder
FormBuilder formBuilder = null;
boolean debugDialog = false;
if (debugDialog) {
JPanel panel = new FormDebugPanel() {
private static final long serialVersionUID = 1L;
@Override
public String getName() {
// this is used as tab title
return Resources
.getString(LocoView.class,
"title." + (LocoView.this.locoConfigModel.isCarControlEnabled() ? "car" : "loco"));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(super.getPreferredSize().width + 20, super.getPreferredSize().height);
}
};
formBuilder =
FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
}
else {
JPanel panel = new JPanel(new BorderLayout()) {
private static final long serialVersionUID = 1L;
@Override
public String getName() {
// this is used as tab title
return Resources
.getString(LocoView.class,
"title." + (LocoView.this.locoConfigModel.isCarControlEnabled() ? "car" : "loco"));
}
};
formBuilder =
FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
}
formBuilder.border(Paddings.TABBED_DIALOG);
try {
formBuilder.add(createLocoAddressPanel()).xy(1, 1);
}
catch (Exception ex) {
LOGGER.warn("Create loco address panel failed.", ex);
}
try {
formBuilder.add(directionPanel = createDirectionPanel()).xy(1, 3);
DisabledPanel.disable(directionPanel);
formBuilder.add(createSpeedGaugePanel()).xy(3, 3);
}
catch (Exception ex) {
LOGGER.warn("Create direction panel failed.", ex);
}
final List functionButtons = new LinkedList();
try {
formBuilder.add(lightAndStopButtonPanel = createLightAndStopButtonPanel(functionButtons)).xyw(1, 5, 3);
DisabledPanel.disable(lightAndStopButtonPanel);
}
catch (Exception ex) {
LOGGER.warn("Create light and buttons panel failed.", ex);
}
int row = 11;
try {
formBuilder.add(functionButtonPanel = createFunctionButtonPanel(functionButtons)).xyw(1, 7, 1);
DisabledPanel.disable(functionButtonPanel);
// TODO
// imageOrVideoContainerPanel = new JPanel();
// imageOrVideoContainerPanel.setOpaque(false);
// formBuilder.add(imageOrVideoContainerPanel).xyw(3, 7, 1);
//
// imagePanel = createImagePanel(functionButtons);
// if (locoModel.isCarControlEnabled()) {
// imageOrVideoContainerPanel.add(imagePanel);
// }
if (this.locoConfigModel.isCarControlEnabled()) {
// add the RF basis buttons
this.multiRfBaseButtonPanel = addMultiRfBasisButtons();
formBuilder.add(this.multiRfBaseButtonPanel).xyw(1, 9, 1);
DisabledPanel.disable(this.multiRfBaseButtonPanel);
formBuilder.add(counterPanel = addCounterPanel()).xyw(3, 9, 1);
DisabledPanel.disable(counterPanel);
if (settingsService.getWizardSettings().isPowerUser()) {
formBuilder.appendRows("3dlu, pref");
formBuilder.add(directBinStatePanel = addDirectBinStatePanel()).xy(1, row);
DisabledPanel.disable(directBinStatePanel);
row += 2;
}
}
else {
LOGGER.info("No multi RF basis buttons added.");
}
}
catch (Exception ex) {
LOGGER.warn("Create function buttons panel failed.", ex);
}
// prepare the script panel
scriptPanel = new ScriptPanel(this, settingsService);
addLocoViewListener(scriptPanel);
JPanel panel = scriptPanel.createPanel();
panel
.setBorder(BorderFactory
.createTitledBorder(BorderFactory.createEtchedBorder(),
Resources.getString(getClass(), "script") + ":"));
formBuilder.appendRows("3dlu, pref");
formBuilder.add(panel).xyw(1, row, 3);
// add loco model listener
this.locoModelListener = new LocoModelListener() {
@Override
public void functionChanged(int index, boolean value) {
SwingUtils.executeInEDT(() -> functionButtons.get(index).setSelected(value));
}
@Override
public void binaryStateChanged(int state, boolean value) {
}
};
this.locoModel.addLocoModelListener(this.locoModelListener);
this.locoModelPropertyChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
SwingUtils.executeInEDT(() -> handlePropertyChangeEvent(evt));
}
};
this.locoModel.addPropertyChangeListener(this.locoModelPropertyChangeListener);
contentPanel = formBuilder.build();
addressChangeHandler = new EmptyAddressHandler(value -> {
SwingUtils.executeInEDT(() -> {
LOGGER.info("The address value is not empty: {}", value);
if (value.booleanValue()) {
// check the locoModel
SpeedSteps speedSteps = this.locoModel.getSpeedSteps();
speedStepsCombo.setSelectedItem(speedSteps);
DisabledPanel.enable(directionPanel);
DisabledPanel.enable(lightAndStopButtonPanel);
DisabledPanel.enable(functionButtonPanel);
if (multiRfBaseButtonPanel != null) {
DisabledPanel.enable(multiRfBaseButtonPanel);
}
if (counterPanel != null) {
DisabledPanel.enable(counterPanel);
}
if (directBinStatePanel != null) {
DisabledPanel.enable(directBinStatePanel);
}
}
else {
DisabledPanel.disable(directionPanel);
DisabledPanel.disable(lightAndStopButtonPanel);
DisabledPanel.disable(functionButtonPanel);
if (multiRfBaseButtonPanel != null) {
DisabledPanel.disable(multiRfBaseButtonPanel);
}
if (counterPanel != null) {
DisabledPanel.disable(counterPanel);
}
if (directBinStatePanel != null) {
DisabledPanel.disable(directBinStatePanel);
}
}
});
});
this.addressChangeConnector =
WizardPropertyConnector
.connect(this.locoModel, LocoModel.PROPERTY_ADDRESS, addressChangeHandler,
EmptyAddressHandler.PROPERTYNAME_ADDRESS);
this.addressChangeConnector.updateProperty2();
}
private final EmptyAddressHandler addressChangeHandler;
private void handlePropertyChangeEvent(final PropertyChangeEvent evt) {
// LOGGER.info(">>> Received pce: {}", evt);
switch (evt.getPropertyName()) {
case LocoModel.PROPERTY_ADDRESS:
LOGGER.info("The address has changed, set the reported speed and dynState energy to 0.");
// locoModel.setReportedSpeed(0);
// locoModel.setDynStateEnergy(0);
break;
case LocoModel.PROPERTY_SPEED:
LOGGER.info("The speed has changed: {}", locoModel.getSpeed());
try {
// Integer speedValue = (Integer) evt.getNewValue();
Integer speedValue = locoModel.getSpeed();
if (speedValue != null) {
int speed = speedValue.intValue();
speed =
ConversionUtils
.bidibSpeedToDccSpeed(speed, locoModel.getSpeedSteps() != null
? locoModel.getSpeedSteps().getType() : SpeedStepsEnum.DCC128);
if (speed == 0 || speed == 1) {
LOGGER.info("The current speed is stop or emergengy stop: {}", speed);
changeSliderSilently(0);
}
else {
if (DirectionStatus.BACKWARD == locoModel.getDirection()) {
speed = -speed;
}
LOGGER.info("Set the current speed value: {}", speed);
changeSliderSilently(speed);
}
}
}
catch (Exception ex) {
LOGGER.warn("Set speed failed.", ex);
}
break;
case LocoModel.PROPERTY_SPEED_STEPS:
SpeedSteps speedSteps = locoModel.getSpeedSteps();
LOGGER.info(">>> The speed steps have changed: {}", speedSteps);
if (speedSteps != null) {
// get the listeners
final ChangeListener[] changeListeners = speedSlider.getChangeListeners();
try {
for (ChangeListener cl : changeListeners) {
speedSlider.removeChangeListener(cl);
}
int steps = speedSteps.getSteps() - 1;
speedSlider.setMaximum(steps);
if (locoConfigModel.isCarControlEnabled()) {
speedSlider.setMinimum(0);
}
else {
speedSlider.setMinimum(-steps);
}
speedSlider.setMajorTickSpacing(steps);
}
finally {
for (ChangeListener cl : changeListeners) {
speedSlider.addChangeListener(cl);
}
}
}
LOGGER.info("<<< The speed steps have changed: {}", speedSteps);
break;
case LocoListModel.PROPERTY_FUNCTIONS:
LOGGER.info("The functions have changed: {}", locoModel.getFunctions());
// update the functions
updateFunctionState(locoModel.getFunctions(), functionButtonMap);
break;
case LocoModel.PROPERTY_DYNSTATE_ENERGY:
final int dynStateEnergy = locoModel.getDynStateEnergy();
LOGGER.info("The dynStateEnergy has changed, dynStateEnergy: {}", dynStateEnergy);
if (ledBarGraph != null) {
SwingUtils.executeInEDT(() -> ledBarGraph.setValue(dynStateEnergy));
}
break;
case LocoModel.PROPERTY_REPORTED_SPEED:
Integer reportedSpeed = locoModel.getReportedSpeed();
LOGGER
.info("The reported speed has changed in the locoModel. Send the new speed value: {}",
reportedSpeed);
break;
default:
break;
}
}
protected Map getFunctionButtonMap() {
return functionButtonMap;
}
private void changeSliderSilently(int speed) {
ChangeListener[] changeListeners = speedSlider.getChangeListeners();
// remove the change listeners to prevent signal the speed change to the interface
// twice
for (ChangeListener listener : changeListeners) {
speedSlider.removeChangeListener(listener);
}
try {
speedSlider.setValue(speed);
}
finally {
// add the change listeners again
for (ChangeListener listener : changeListeners) {
speedSlider.addChangeListener(listener);
}
}
}
@Override
public JPanel getComponent() {
return contentPanel;
}
private JPanel createLocoAddressPanel() {
final FormBuilder formBuilder =
FormBuilder
.create().columns("pref, 3dlu, 40dlu, 10dlu, pref, 3dlu, 60dlu, 10dlu, pref, 3dlu:grow").rows("pref");
// formBuilder.debug(true);
address = new JTextField();
address.setDocument(new InputValidationDocument(5, InputValidationDocument.NUMERIC));
// set the default address
if (locoModel.getAddress() != null) {
address.setText(Integer.toString(locoModel.getAddress()));
}
else {
address.setText(null);
}
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() {
Integer currentAddress = null;
if (!address.getText().isEmpty()) {
try {
currentAddress = Integer.valueOf(address.getText());
}
catch (NumberFormatException e) {
LOGGER.warn("Parse decoder address failed.");
return;
}
}
// check if the address has been changed
if (locoModel != null && (currentAddress == null && locoModel.getAddress() == null)
|| currentAddress != null && currentAddress.equals(locoModel.getAddress())) {
LOGGER.info("Address has not been changed.");
return;
}
LOGGER.info("Get the locoModel for the new address: {}", currentAddress);
locoAddressChangeListener.accept(currentAddress);
// must reset the reported cell number
// locoModel.setReportedCellNumber(null);
}
});
formBuilder.add(Resources.getString(getClass(), "address")).xy(1, 1);
formBuilder.add(address).xy(3, 1);
if (m4SupportEnabled) {
speedStepsCombo = new JComboBox(SpeedSteps.values());
}
else {
// filter the M4 speed steps
List speedSteps = new ArrayList<>();
speedSteps.addAll(Arrays.asList(SpeedSteps.values()));
CollectionUtils.filter(speedSteps, new Predicate() {
@Override
public boolean evaluate(SpeedSteps speedStep) {
return (speedStep.ordinal() <= SpeedSteps.DCC_SDF.ordinal());
}
});
speedStepsCombo = new JComboBox(speedSteps.toArray(new SpeedSteps[0]));
}
speedStepsCombo
.setSelectedItem(locoModel.getSpeedSteps() != null ? locoModel.getSpeedSteps() : SpeedSteps.DCC128);
speedStepsCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Speed steps combo has changed, update loco model.");
LocoView.this.locoControlListener.setSpeedSteps((SpeedSteps) speedStepsCombo.getSelectedItem());
}
});
formBuilder.add(Resources.getString(getClass(), "speedSteps")).xy(5, 1);
formBuilder.add(speedStepsCombo).xyw(7, 1, 1);
final JButton removeButton = new JButton(Resources.getString(LocoView.class, "remove"));
removeButton.setToolTipText(Resources.getString(LocoView.class, "remove.tooltip"));
removeButton.addActionListener(evt -> {
LOGGER.info("Remove loco from DCC refresh.");
LocoView.this.locoControlListener.clearLoco();
});
formBuilder.add(removeButton).xyw(9, 1, 2);
return formBuilder.build();
}
private JPanel createDirectionPanel() {
final FormBuilder formBuilder =
FormBuilder
.create().columns("pref, 3dlu, 60dlu:grow, 3dlu, pref")
.rows("pref, 3dlu, pref, 3dlu, pref, 3dlu, pref");
formBuilder.border(new EmptyBorder(10, 0, 10, 0));
// TODO the speed value must honour the speed steps
final ValueModel speedModel = new SwingPropertyAdapter(locoModel, LocoModel.PROPERTY_SPEED, true);
final ValueModel speedConverterModel =
new ConverterValueModel(speedModel,
new BidibSpeedToDccSpeedConverter(() -> locoModel.getSpeedSteps(), () -> locoModel.getDirection()));
speed = WizardComponentFactory.createLabel(speedConverterModel);
formBuilder.add(Resources.getString(getClass(), "speed")).xy(1, 1);
formBuilder.add(speed).xy(3, 1);
final ValueModel reportedSpeedModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTY_REPORTED_SPEED, true);
final ValueModel reportedSpeedConverterModel =
new ConverterValueModel(reportedSpeedModel, new StringConverter(new DecimalFormat("#")));
reportedSpeed = WizardComponentFactory.createLabel(reportedSpeedConverterModel);
formBuilder.add(Resources.getString(getClass(), "reportedSpeed")).xy(1, 3);
formBuilder.add(reportedSpeed).xy(3, 3);
speedSlider = new JZeroSlider();
speedSlider.setOpaque(FormsSetup.getOpaqueDefault());
int steps =
locoModel.getSpeedSteps() != null ? locoModel.getSpeedSteps().getSteps() - 1
: SpeedSteps.DCC128.getSteps() - 1;
speedSlider.setMaximum(steps);
if (locoConfigModel.isCarControlEnabled()) {
speedSlider.setMinimum(0);
}
else {
speedSlider.setMinimum(-steps);
}
speedSlider.setPaintTicks(true);
InputMap keyMap = (InputMap) UIManager.get("Slider.focusInputMap", speedSlider.getLocale());
if (LOGGER.isDebugEnabled()) {
if (keyMap != null) {
Object binding = keyMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0));
LOGGER.debug("HOME is binded: {}", binding);
}
}
speedSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), "speedToMaxValue");
speedSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), "speedToMinValue");
speedSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "speedUpValue");
speedSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "speedDownValue");
speedSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "speedStop");
speedSlider.getActionMap().put("speedToMaxValue", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("speedToMaxValue was called.");
DirectionStatus dir = locoModel.getDirection();
int steps = locoModel.getSpeedSteps().getSteps() - 1;
if (DirectionStatus.FORWARD == dir) {
speedSlider.setValue(steps);
}
else {
speedSlider.setValue(-steps);
}
}
});
speedSlider.getActionMap().put("speedToMinValue", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("speedToMinValue was called.");
speedSlider.setValue(0);
}
});
speedSlider.getActionMap().put("speedUpValue", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// increase speed
Integer speed = locoModel.getSpeed();
DirectionStatus dir = locoModel.getDirection();
LOGGER.info("speedUpValue was called, current speed: {}, dir: {}", speed, dir);
if (speed == null) {
speed = 0;
}
if (dir == DirectionStatus.FORWARD) {
if (speed < steps) {
speed += PAGE_STEPS;
}
if (speed > steps) {
speed = steps;
}
}
else {
// BACKWARDS
if (speed > 0) {
speed -= PAGE_STEPS + 1;
if (speed < 0) {
speed = 0;
}
// provide negative speed
speed = -speed;
}
else if (speed == 0) {
// change the direction
LOGGER.info("The speed is 0 and we must change the direction and increase speed.");
speed += PAGE_STEPS;
}
}
LOGGER.info("speedUpValue was called, new speed: {}", speed);
speedSlider.setValue(speed);
}
});
speedSlider.getActionMap().put("speedDownValue", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
// decrease speed
Integer speed = locoModel.getSpeed();
DirectionStatus dir = locoModel.getDirection();
LOGGER.info("speedDownValue was called, current speed: {}, dir: {}", speed, dir);
if (speed == null) {
speed = 0;
}
if (dir == DirectionStatus.FORWARD) {
if (speed > 0) {
speed -= PAGE_STEPS + 1;
if (speed < 0) {
speed = 0;
}
}
else if (speed == 0) {
// change the direction
LOGGER.info("The speed is 0 and we must change the direction and 'increase' speed.");
speed += PAGE_STEPS;
// provide negative speed
speed = -speed;
}
}
else {
// BACKWARDS
if (speed < steps) {
speed += PAGE_STEPS;
}
if (speed > steps) {
speed = steps;
}
speed = -speed;
}
LOGGER.info("speedDownValue was called, new speed: {}", speed);
speedSlider.setValue(speed);
}
});
speedSlider.getActionMap().put("speedStop", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("speedStop was called.");
fireStop();
}
});
// init value before add the change listener because otherwise stops the loco ...
speedSlider.setValue(0);
speedSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
if (!source.getValueIsAdjusting()) {
int value = speedSlider.getValue();
LOGGER.info("Current speedSlider value: {}", value);
DirectionStatus direction = null;
if (value > 0) {
direction = DirectionStatus.FORWARD;
// value++;
}
else if (value < 0) {
direction = DirectionStatus.BACKWARD;
// value--;
}
value = Math.abs(value);
LOGGER.info("Set the speed value: {}", value);
// TODO this is no longer correct
// locoModel.setSpeed(value);
LocoView.this.locoControlListener.setSpeed(value, direction);
}
}
});
// let the slider jump to the position the user clicked
speedSlider.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
JSlider sourceSlider = (JSlider) e.getSource();
BasicSliderUI ui = (BasicSliderUI) sourceSlider.getUI();
int value = ui.valueForXPosition(e.getX());
// consume the mouse event to no let the other listeners be triggered
e.consume();
LOGGER.info("Mouse pressed on slider. Set the new value: {}", value);
speedSlider.setValue(value);
}
});
// allow control speed with mouse wheel
int speedDelta = 1;
this.speedSlider.addMouseWheelListener(evt -> {
if (evt.getWheelRotation() < 0)// mouse wheel was rotated up/away from the user
{
int iNewValue = this.speedSlider.getValue() - speedDelta;
if (iNewValue >= this.speedSlider.getMinimum()) {
this.speedSlider.setValue(iNewValue);
}
else {
this.speedSlider.setValue(0);
}
}
else {
int iNewValue = this.speedSlider.getValue() + speedDelta;
if (iNewValue <= this.speedSlider.getMaximum()) {
this.speedSlider.setValue(iNewValue);
}
else {
this.speedSlider.setValue(this.speedSlider.getMaximum());
}
}
});
formBuilder.add(speedSlider).xyw(1, 5, 5);
final JLabel minimumValueLabel = new JLabel(Resources.getString(getClass(), "backwards"));
formBuilder.add(minimumValueLabel).xy(1, 7);
if (locoConfigModel.isCarControlEnabled()) {
minimumValueLabel.setText(Resources.getString(LocoView.class, "stop"));
}
formBuilder.add(Resources.getString(LocoView.class, "forwards")).xy(5, 7);
JPanel helperPanel = new JPanel(new BorderLayout());
helperPanel.setOpaque(false);
ledBarGraph = new LedBarGraph(10, Orientation.vertical);
ledBarGraph.setOpaque(FormsSetup.getOpaqueDefault());
helperPanel.add(formBuilder.build(), BorderLayout.CENTER);
helperPanel.add(ledBarGraph, BorderLayout.EAST);
locoModel.addPropertyChangeListener(LocoConfigModel.PROPERTY_CARCONTROL_ENABLED, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
LOGGER.info(">>> Received pce: {}", evt);
if (LocoConfigModel.PROPERTY_CARCONTROL_ENABLED.equals(evt.getPropertyName())) {
SwingUtils.executeInEDT(() -> {
LOGGER.info("The car control enabled flag has changed.");
if (locoModel.getSpeedSteps() != null) {
int steps = locoModel.getSpeedSteps().getSteps() - 1;
speedSlider.setMaximum(steps);
if (locoConfigModel.isCarControlEnabled()) {
// remove the speed after change slider range
try {
speedSlider.setMinimum(0);
}
finally {
// locoModel.setSpeed(null);
LocoView.this.locoControlListener.setSpeed(null, null);
}
minimumValueLabel.setText(Resources.getString(LocoView.class, "stop"));
// imageOrVideoContainerPanel.add(imagePanel);
}
else {
// remove the speed after change slider range
try {
speedSlider.setMinimum(-steps);
}
finally {
// locoModel.setSpeed(null);
LocoView.this.locoControlListener.setSpeed(null, null);
}
// imageOrVideoContainerPanel.remove(imagePanel);
}
}
});
}
}
});
locoModel.addPropertyChangeListener(LocoModel.PROPERTY_SPEED, evt -> {
LOGGER.info(">>> Received pce: {}", evt);
if (LocoModel.PROPERTY_SPEED.equals(evt.getPropertyName())) {
SwingUtils.executeInEDT(() -> {
boolean stopped = isSpeedStopped(locoModel.getSpeed());
speedStepsCombo.setEnabled(stopped);
});
}
});
// locoModel.addPropertyChangeListener(LocoModel.PROPERTY_REPORTED_SPEED, evt -> {
// LOGGER.info(">>> Received pce: {}", evt);
//
// if (LocoModel.PROPERTY_REPORTED_SPEED.equals(evt.getPropertyName())) {
//
// SwingUtils.executeInEDT(() -> {
// LOGGER.info("Set the reported speed: {}", locoModel.getReportedSpeed());
//
// Integer reportedSpeedValue = locoModel.getReportedSpeed();
// reportedSpeed.setText(reportedSpeedValue != null ? reportedSpeedValue.toString() : null);
// });
// }
// });
boolean stopped = isSpeedStopped(locoModel.getSpeed());
speedStepsCombo.setEnabled(stopped);
return helperPanel;
}
private boolean isSpeedStopped(Integer speed) {
boolean stopped = false;
if (speed != null) {
switch (speed.intValue()) {
case 0:
case 1:
// stopped
stopped = true;
break;
default:
break;
}
}
else {
// assume stopped
stopped = true;
}
return stopped;
}
private JComponent createSpeedGaugePanel() {
final Radial speedGauge = SpeedGaugeBuilder.speedGauge("Speed", "km/h");
JPanel panel = new JPanel() {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
panel.setOpaque(false);
panel.setLayout(new BorderLayout());
panel.add(speedGauge, BorderLayout.CENTER);
final ValueModel reportedSpeedModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTY_REPORTED_SPEED, true);
Bindings.bind(speedGauge, "valueAnimated", reportedSpeedModel);
return panel;
}
private JPanel createLightAndStopButtonPanel(final List functionButtons) {
final FormBuilder formBuilder = FormBuilder.create().columns("pref, 3dlu, 60dlu:grow, 3dlu, pref").rows("pref");
// add the light icons
ImageIcon lightOnIcon = ImageUtils.createImageIcon(LocoView.class, "/icons/16x16/lightbulb.png");
ImageIcon lightOffIcon = ImageUtils.createImageIcon(LocoView.class, "/icons/16x16/lightbulb_off.png");
final JideToggleButton lightButton = new JideToggleButton(lightOffIcon);
lightButton.setSelectedIcon(lightOnIcon);
lightButton.setRolloverSelectedIcon(lightOnIcon);
lightButton.setButtonStyle(JideButton.TOOLBOX_STYLE);
lightButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// locoModel.setFunction(0, lightButton.isSelected());
LocoView.this.locoControlListener.setFunction(0, lightButton.isSelected());
}
});
functionButtons.add(lightButton);
functionButtonMap.put("F0", lightButton);
formBuilder.add(lightButton).xy(1, 1);
lightButton.setSelected(locoModel.getFunction(LocoModel.FUNCTIONINDEX_LIGHTS));
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();
}
});
stopEmergencyButton = new JButton(Resources.getString(getClass(), "emergencyStop"));
stopEmergencyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireEmergencyStop();
}
});
JPanel buttonPanel = new ButtonBarBuilder().addGlue().addButton(stopButton, stopEmergencyButton).build();
formBuilder.add(buttonPanel).xy(3, 1);
return formBuilder.build();
}
private JPanel createFunctionButtonPanel(final List functionButtons) {
final FormBuilder formBuilder =
FormBuilder
.create()
.columns(
"pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref, 8dlu, pref")
.rows("pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref");
formBuilder.addSeparator(Resources.getString(getClass(), "additionalFunctions")).xyw(1, 1, 19);
final int columns = 10;
for (int row = 0; row < 4; row++) {
for (int column = 0; column < columns; column++) {
final int functionIndex = row * columns + (column + 1);
String buttonText = "F" + functionIndex;
if (functionIndex > 28) {
buttonText = "B" + functionIndex;
}
// use JideToggleButton for function and binary function buttons
final JideButton functionButton = new JideToggleButton(buttonText);
functionButton.setButtonStyle(JideButton.TOOLBOX_STYLE);
functionButton.addActionListener(event -> {
LOGGER.info("Set function with index: {}", functionIndex);
if (functionIndex < 29) {
LocoView.this.locoControlListener.setFunction(functionIndex, functionButton.isSelected());
}
else {
LocoView.this.locoControlListener.setBinaryState(functionIndex, true);
}
});
functionButtons.add(functionButton);
functionButtonMap.put(buttonText, functionButton);
formBuilder.add(functionButton).xy((column * 2) + 1, (row * 2) + 3);
}
}
return formBuilder.build();
}
protected void updateFunctionState(final BitSet functions, final Map functionButtonMap) {
int maxFunctionIndex = functions.size();
LOGGER.info("Current functions count: {}", maxFunctionIndex);
for (int index = 0; index < maxFunctionIndex; index++) {
if (index < 29) {
String buttonText = "F" + index;
boolean value = functions.get(index);
JButton functionButton = functionButtonMap.get(buttonText);
if (functionButton != null) {
functionButton.setSelected(value);
}
else {
LOGGER.warn("No functionButton available for index: {}", index);
}
}
else {
String buttonText = "B" + index;
boolean value = functions.get(index);
JButton functionButton = functionButtonMap.get(buttonText);
if (functionButton != null) {
functionButton.setSelected(value);
}
else {
LOGGER.warn("No binary functionButton available for index: {}", index);
}
}
}
}
private JComponent[] rfBaseButtons;
private JPanel addMultiRfBasisButtons() {
final FormBuilder formBuilder =
FormBuilder
.create()
.columns(
"pref, 5dlu, pref, 5dlu, pref, 5dlu, pref, 5dlu, pref, 5dlu, pref, 5dlu, pref, 5dlu, pref:grow")
.rows("pref, 3dlu, pref");
formBuilder.addSeparator(Resources.getString(getClass(), "multiRFBasis")).xyw(1, 1, 15);
ValueModel activeBaseModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTY_ACTIVE_BASE, true);
// add the radio buttons for the basis change
rfBaseButtons = new JComponent[RfBasisMode.values().length];
int column = 0;
int col = 0;
int row = 3;
for (RfBasisMode rfBaseMode : RfBasisMode.values()) {
JRadioButton radio =
WizardComponentFactory
.createRadioButton(activeBaseModel, rfBaseMode,
Resources.getString(RfBasisMode.class, rfBaseMode.getKey()));
rfBaseButtons[column] = radio;
// add radio button
formBuilder.add(radio).xy(col * 2 + 1, row);
column++;
col++;
if (rfBaseMode == RfBasisMode.SINGLE) {
formBuilder.appendRows("3dlu, pref");
col = 0;
row += 2;
}
}
formBuilder.appendRows("3dlu, pref");
col = 0;
row += 2;
ValueModel reportedCellNumberModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTY_REPORTED_CELLNUMBER, true);
final ValueModel reportedCellNumberConverterModel =
new ConverterValueModel(reportedCellNumberModel, new StringConverter(new DecimalFormat("#")));
JTextField reportedCellNumberText =
WizardComponentFactory.createTextField(reportedCellNumberConverterModel, false);
reportedCellNumberText.setEditable(false);
formBuilder.add("Reported RF Cellnumber").xyw(1, row, 5);
formBuilder.add(reportedCellNumberText).xy(7, row);
activeBaseModel.addValueChangeListener(evt -> {
LOGGER.info("The active RF base has changed: {}", evt.getNewValue());
RfBasisMode activeRfBase = locoModel.getActiveBase();
if (activeRfBase != null) {
final Integer functionIndex = activeRfBase.getFunctionIndex();
if (functionIndex != null) {
// send the binary state
LocoView.this.locoControlListener.setBinaryState(functionIndex, true);
}
}
});
return formBuilder.build();
}
private JPanel addCounterPanel() {
final FormBuilder formBuilder =
FormBuilder
.create().columns("pref, 5dlu, pref:grow").rows("pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref");
formBuilder.addSeparator(Resources.getString(getClass(), "Counter")).xyw(1, 1, 3);
// CS_DRIVE
ValueModel counterCsDriveModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTYNAME_COUNTER_CS_DRIVE, true);
final ValueModel counterCsDriveConverterModel =
new ConverterValueModel(counterCsDriveModel, new StringConverter(new DecimalFormat("#")));
JTextField counterCsDriveText = WizardComponentFactory.createTextField(counterCsDriveConverterModel, false);
counterCsDriveText.setEditable(false);
formBuilder.add("CS_DRIVE").xy(1, 3);
formBuilder.add(counterCsDriveText).xy(3, 3);
// CS_BIN_STATE
ValueModel counterCsBinStateModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTYNAME_COUNTER_CS_BIN_STATE, true);
final ValueModel counterCsBinStateConverterModel =
new ConverterValueModel(counterCsBinStateModel, new StringConverter(new DecimalFormat("#")));
JTextField counterCsBinStateText =
WizardComponentFactory.createTextField(counterCsBinStateConverterModel, false);
counterCsBinStateText.setEditable(false);
formBuilder.add("CS_BIN_STATE").xy(1, 5);
formBuilder.add(counterCsBinStateText).xy(3, 5);
// CS_DRIVE_ACK
ValueModel counterCsDriveAckModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTYNAME_COUNTER_CS_DRIVE_ACK, true);
final ValueModel counterCsDriveAckConverterModel =
new ConverterValueModel(counterCsDriveAckModel, new StringConverter(new DecimalFormat("#")));
JTextField counterCsDriveAckText =
WizardComponentFactory.createTextField(counterCsDriveAckConverterModel, false);
counterCsDriveAckText.setEditable(false);
formBuilder.add("CS_DRIVE_ACK").xy(1, 7);
formBuilder.add(counterCsDriveAckText).xy(3, 7);
// reset button
JButton resetButton = new JButton(Resources.getString(getClass(), "reset"));
resetButton.addActionListener(evt -> {
LOGGER.info("Reset the counters.");
locoModel.resetCounterCsDrive();
locoModel.resetCounterCsAckDrive();
locoModel.resetCounterCsBinState();
});
formBuilder.add(resetButton).xy(1, 9);
return formBuilder.build();
}
private JComponent[] devBinStateValueButtons;
private JPanel addDirectBinStatePanel() {
final FormBuilder formBuilder =
FormBuilder
.create().columns("pref, 5dlu, max(pref;30dlu), 5dlu, pref, 5dlu, pref, 5dlu, pref, 5dlu:grow")
.rows("pref, 3dlu, pref");
formBuilder.addSeparator(Resources.getString(getClass(), "devBinState")).xyw(1, 1, 10);
ValueModel devBinStateNumberModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTYNAME_DEV_BINSTATE_NUMBER, true);
final ValueModel binStateNumberConverterModel =
new ConverterValueModel(devBinStateNumberModel, new StringConverter(new DecimalFormat("#")));
JTextField devBinStateNumberText = WizardComponentFactory.createTextField(binStateNumberConverterModel, false);
InputValidationDocument stateNumberDocument = new InputValidationDocument(5, InputValidationDocument.NUMERIC);
stateNumberDocument.setDocumentFilter(new IntegerRangeFilter(0, 32767));
devBinStateNumberText.setDocument(stateNumberDocument);
formBuilder.add("Number").xy(1, 3);
formBuilder.add(devBinStateNumberText).xy(3, 3);
ValueModel devBinStateValueModel =
new SwingPropertyAdapter(locoModel, LocoModel.PROPERTYNAME_DEV_BINSTATE_VALUE, true);
devBinStateValueButtons = new JComponent[BinStateValue.values().length];
int column = 0;
for (BinStateValue binStateValue : BinStateValue.values()) {
JRadioButton radio =
WizardComponentFactory
.createRadioButton(devBinStateValueModel, binStateValue,
Resources.getString(BinStateValue.class, binStateValue.getKey()));
devBinStateValueButtons[column] = radio;
// add radio button
formBuilder.add(radio).xy(5 + column * 2, 3);
column++;
}
JButton sendButton = new JButton(Resources.getString(getClass(), "send"));
sendButton.addActionListener(evt -> {
BinStateValue devBinStateValue = locoModel.getDevBinStateValue();
if (devBinStateValue != null) {
final boolean functionValue = devBinStateValue.getFunctionValue();
Integer binStateNumber = locoModel.getDevBinStateNumber();
if (binStateNumber != null) {
// send the binary state
LocoView.this.locoControlListener.setBinaryState(binStateNumber.intValue(), functionValue);
}
else {
LOGGER.info("No bin state number available. The BIN_STATE is not fired.");
}
}
});
sendButton.setEnabled(false);
formBuilder.add(sendButton).xy(9, 3);
devBinStateNumberModel.addValueChangeListener(evt -> {
Integer binStateNumber = locoModel.getDevBinStateNumber();
sendButton.setEnabled(binStateNumber != null);
});
return formBuilder.build();
}
private BlinkerLed blinkerRight;
private BlinkerLed blinkerLeft;
private JPanel createImagePanel(final List functionButtons) {
JPanel imagePanel = new JPanel(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
// layeredPane.setLayout(null);
layeredPane.setPreferredSize(new Dimension(140, 140));
// use the image
ImageIcon carFrontIcon = ImageUtils.loadImageIcon(LocoView.class, "/images/Truck-Front.png", 120, 120);
JLabel backgroundLabel = new JLabel(carFrontIcon);
backgroundLabel.setOpaque(true);
// backgroundLabel.setBounds(0, 0, carFrontIcon.getIconWidth(), carFrontIcon.getIconHeight());
backgroundLabel.setBounds(0, 0, 140, 140);
layeredPane.add(backgroundLabel, Integer.valueOf(10));
blinkerRight = new BlinkerLed(0, 0, 8, 6, Color.ORANGE.brighter(), Color.ORANGE);
blinkerLeft = new BlinkerLed(0, 0, 8, 6, Color.ORANGE.brighter(), Color.ORANGE);
final BlinkerLed lightRight = new BlinkerLed(0, 0, 8, 11, Color.YELLOW, Color.WHITE);
final BlinkerLed lightLeft = new BlinkerLed(0, 0, 8, 11, Color.YELLOW, Color.WHITE);
layeredPane.add(blinkerLeft, Integer.valueOf(20));
layeredPane.add(blinkerRight, Integer.valueOf(20));
layeredPane.add(lightLeft, Integer.valueOf(20));
layeredPane.add(lightRight, Integer.valueOf(20));
blinkerLeft.setBounds(37, 84, 10, 7);
blinkerRight.setBounds(93, 84, 10, 7);
lightLeft.setBounds(37, 92, 10, 11);
lightRight.setBounds(93, 92, 10, 11);
final Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
blinkerLeft.setCursor(cursor);
blinkerRight.setCursor(cursor);
lightLeft.setCursor(cursor);
lightRight.setCursor(cursor);
final JideToggleButton functionButtonLeft = getButton(functionButtons.get(2), JideToggleButton.class);
functionButtonLeft.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
blinkerLeft.setActive(functionButtonLeft.isSelected(), true);
}
});
final JideToggleButton functionButtonRight = getButton(functionButtons.get(1), JideToggleButton.class);
functionButtonRight.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
blinkerRight.setActive(functionButtonRight.isSelected(), true);
}
});
final JideToggleButton functionButtonLights = getButton(functionButtons.get(0), JideToggleButton.class);
functionButtonLights.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
LOGGER.info("Lights state has changed, selected: {}", functionButtonLights.isSelected());
lightRight.setActive(functionButtonLights.isSelected(), false);
lightLeft.setActive(functionButtonLights.isSelected(), false);
}
});
backgroundLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
Point point = e.getPoint();
LOGGER.info("Mouse clicked, point: {}", point);
if (point.getX() > 37 && point.getX() < 44) {
// left side
if (point.getY() > 83 && point.getY() < 89) {
// blinker
LOGGER.info("Turn left blinker on/off.");
int functionIndex = 2;
JideToggleButton functionButton =
getButton(functionButtons.get(functionIndex), JideToggleButton.class);
// toggle the button
functionButton.setSelected(!functionButton.isSelected());
LocoView.this.locoControlListener.setFunction(functionIndex, functionButton.isSelected());
}
else if (point.getY() > 91 && point.getY() < 102) {
// front lights
LOGGER.info("Turn front lights on/off.");
int functionIndex = 0;
JideToggleButton functionButton =
getButton(functionButtons.get(functionIndex), JideToggleButton.class);
// toggle the button
functionButton.setSelected(!functionButton.isSelected());
LocoView.this.locoControlListener.setFunction(functionIndex, functionButton.isSelected());
}
}
else if (point.getX() > 93 && point.getX() < 101) {
// right side
if (point.getY() > 83 && point.getY() < 89) {
// blinker
LOGGER.info("Turn right blinker on/off.");
int functionIndex = 1;
JideToggleButton functionButton =
getButton(functionButtons.get(functionIndex), JideToggleButton.class);
// toggle the button
functionButton.setSelected(!functionButton.isSelected());
LocoView.this.locoControlListener.setFunction(functionIndex, functionButton.isSelected());
}
else if (point.getY() > 91 && point.getY() < 102) {
// front lights
LOGGER.info("Turn front lights on/off.");
int functionIndex = 0;
JideToggleButton functionButton =
getButton(functionButtons.get(functionIndex), JideToggleButton.class);
// toggle the button
functionButton.setSelected(!functionButton.isSelected());
LocoView.this.locoControlListener.setFunction(functionIndex, functionButton.isSelected());
}
}
}
});
imagePanel.add(layeredPane, BorderLayout.CENTER);
return imagePanel;
}
private static T getButton(JButton button, Class type) {
// if same type
if (type.isInstance(button)) {
return type.cast(button);
}
throw new IllegalArgumentException("The provided button has not the requested type.");
}
protected void fireWriteState(int state, boolean value) {
LocoView.this.locoControlListener.setBinaryState(state, value);
}
private void addLocoViewListener(LocoViewListener listener) {
locoViewListeners.add(listener);
}
public void addViewCloseListener(ViewCloseListener listener) {
viewCloseListeners.add(listener);
}
private void fireEmergencyStop() {
LocoView.this.locoControlListener.setSpeed(1, null);
for (LocoViewListener listener : locoViewListeners) {
listener.emergencyStop();
}
}
private void fireStop() {
LocoView.this.locoControlListener.setSpeed(0, null);
for (LocoViewListener listener : locoViewListeners) {
listener.stop();
}
}
@Override
public void selectDecoderAddress(int dccAddress) {
LOGGER.info("Select the decoder address: {}", dccAddress);
address.setText(String.valueOf(dccAddress));
// set the speed to null because we want the new speed value triggered
LocoView.this.locoControlListener.setSpeed(null, null);
}
@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);
changeSliderSilently(speed);
LocoView.this.locoControlListener.setSpeed(speed, null);
}
@Override
public void setFunction(int function) {
LOGGER.info("Set the function: {}", function);
JideToggleButton functionButton = getButton(functionButtonMap.get("F" + function), JideToggleButton.class);
LOGGER.warn("Fetched functionButton: {}", functionButton);
functionButton.doClick();
}
@Override
public void setBinState(int binStateNumber, boolean flag) {
LOGGER.info("Set the binState, binStateNumber: {}, flag: {}", binStateNumber, flag);
// send the binary state
LocoView.this.locoControlListener.setBinaryState(binStateNumber, flag);
}
@Override
public void setStop() {
LOGGER.info("Set stop.");
stopButton.doClick();
}
@Override
public void setStopEmergency() {
LOGGER.info("Set stop emergency.");
stopEmergencyButton.doClick();
}
public void cleanup(final SettingsService settingsService) {
LOGGER.info("The LocoView is disposed. Remove all listeners from the locoModel.");
for (ViewCloseListener closeListener : viewCloseListeners) {
try {
closeListener.close();
}
catch (Exception ex) {
LOGGER.warn("Notify view close listener failed.", ex);
}
}
final SpeedSteps lastSelectedSpeedSteps = this.locoModel.getSpeedSteps();
settingsService.getWizardSettings().setLastSelectedSpeedSteps(lastSelectedSpeedSteps);
if (blinkerLeft != null) {
blinkerLeft.setActive(false, true);
}
if (blinkerRight != null) {
blinkerRight.setActive(false, true);
}
viewCloseListeners.clear();
locoViewListeners.clear();
// if (locoModelListener != null) {
this.locoModel.removeLocoModelListener(locoModelListener);
// locoModelListener = null;
// }
this.locoModel.removePropertyChangeListener(this.locoModelPropertyChangeListener);
this.addressChangeConnector.release();
if (scriptPanel != null) {
scriptPanel.close();
scriptPanel = null;
}
functionButtonMap.clear();
}
private static class BlinkerLed extends JComponent {
private static final long serialVersionUID = 1L;
private Timer blinkerTimer;
private Color colorOn;
private Color colorOff;
private boolean on;
private int x;
private int y;
private int width;
private int height;
public BlinkerLed(int x, int y, int width, int height, Color colorOn, Color colorOff) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.colorOn = colorOn;
this.colorOff = colorOff;
}
public void setActive(boolean active, boolean useTimer) {
repaint();
if (active) {
if (useTimer && blinkerTimer == null) {
blinkerTimer = new Timer(500, evt -> {
on = !on;
repaint();
});
}
on = true;
if (blinkerTimer != null) {
blinkerTimer.start();
}
}
else if (!active) {
on = false;
if (blinkerTimer != null) {
blinkerTimer.stop();
}
}
}
@Override
public void paintComponent(Graphics graphics) {
if (on) {
graphics.setColor(colorOn);
}
else {
graphics.setColor(colorOff);
}
graphics.fillRect(x, y, width, height);
}
}
}