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

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

There is a newer version: 2.0.0-M1
Show newest version
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