ch.fork.AdHocRailway.ui.locomotives.configuration.LocomotiveConfig.java Source code

Java tutorial

Introduction

Here is the source code for ch.fork.AdHocRailway.ui.locomotives.configuration.LocomotiveConfig.java

Source

/*------------------------------------------------------------------------
 * 
 * copyright : (C) 2008 by Benjamin Mueller 
 * email     : news@fork.ch
 * website   : http://sourceforge.net/projects/adhocrailway
 * version   : $Id$
 * 
 *----------------------------------------------------------------------*/

/*------------------------------------------------------------------------
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 *----------------------------------------------------------------------*/

package ch.fork.AdHocRailway.ui.locomotives.configuration;

import ch.fork.AdHocRailway.domain.locomotives.Locomotive;
import ch.fork.AdHocRailway.domain.locomotives.LocomotiveFunction;
import ch.fork.AdHocRailway.domain.locomotives.LocomotiveGroup;
import ch.fork.AdHocRailway.domain.locomotives.LocomotiveType;
import ch.fork.AdHocRailway.manager.LocomotiveManager;
import ch.fork.AdHocRailway.manager.ManagerException;
import ch.fork.AdHocRailway.ui.context.LocomotiveContext;
import ch.fork.AdHocRailway.ui.locomotives.LocomotiveImageHelper;
import ch.fork.AdHocRailway.ui.utils.GlobalKeyShortcutHelper;
import ch.fork.AdHocRailway.ui.utils.ImageTools;
import ch.fork.AdHocRailway.ui.utils.SwingUtils;
import ch.fork.AdHocRailway.ui.utils.UIConstants;
import ch.fork.AdHocRailway.ui.widgets.ErrorPanel;
import ch.fork.AdHocRailway.ui.widgets.ImagePreviewPanel;
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.adapter.SpinnerAdapterFactory;
import com.jgoodies.binding.list.ArrayListModel;
import com.jgoodies.binding.list.SelectionInList;
import com.jgoodies.binding.value.Trigger;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import de.dermoba.srcp.model.turnouts.MMTurnout;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Arrays;
import java.util.List;

public class LocomotiveConfig extends JDialog implements PropertyChangeListener {

    private final Trigger trigger = new Trigger();
    private LocomotiveContext ctx;
    private boolean createLocomotive;
    private PresentationModel<Locomotive> presentationModel;
    private JTextField nameTextField;
    private JSpinner busSpinner;
    private JSpinner address1Spinner;
    private JSpinner address2Spinner;
    private JTextField descTextField;
    private JTextField imageTextField;
    @SuppressWarnings("rawtypes")
    private JComboBox<LocomotiveType> locomotiveTypeComboBox;
    private JButton okButton;
    private JButton cancelButton;
    private JLabel imageLabel;
    private JPanel imageChoserPanel;
    private JButton chooseImageButton;
    private LocomotiveGroup selectedLocomotiveGroup;
    private JTable functionsTable;
    private ArrayListModel<LocomotiveFunction> functions;
    private ErrorPanel errorPanel;
    private SelectionInList<LocomotiveFunction> functionsModel;

    public LocomotiveConfig(final LocomotiveContext ctx, final Frame owner, final Locomotive myLocomotive,
            final LocomotiveGroup selectedLocomotiveGroup, boolean createLocomotive) {
        super(owner, "Locomotive Config", true);
        init(ctx, myLocomotive, selectedLocomotiveGroup, createLocomotive);
    }

    public LocomotiveConfig(final LocomotiveContext ctx, final JDialog owner, final Locomotive myLocomotive,
            final LocomotiveGroup selectedLocomotiveGroup, boolean createLocomotive) {
        super(owner, "Locomotive Config", true);
        init(ctx, myLocomotive, selectedLocomotiveGroup, createLocomotive);
    }

    private void init(LocomotiveContext ctx, Locomotive myLocomotive, LocomotiveGroup selectedLocomotiveGroup,
            boolean createLocomotive) {
        this.ctx = ctx;
        this.createLocomotive = createLocomotive;
        this.selectedLocomotiveGroup = selectedLocomotiveGroup;
        this.presentationModel = new PresentationModel<Locomotive>(myLocomotive, trigger);
        initGUI();
    }

    private void initGUI() {
        buildPanel();
        initShortcuts();
        nameTextField.requestFocus();
        pack();
        SwingUtils.addEscapeListener(this);
        setLocationRelativeTo(getParent());
        setVisible(true);
    }

    private void initShortcuts() {
        GlobalKeyShortcutHelper.registerKey(getRootPane(), KeyEvent.VK_ENTER, 0, new ApplyChangesAction());
    }

    private void initComponents() {

        nameTextField = BasicComponentFactory
                .createTextField(presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_NAME));
        nameTextField.setColumns(30);

        descTextField = BasicComponentFactory
                .createTextField(presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_DESCRIPTION));
        descTextField.setColumns(30);

        imageChoserPanel = new JPanel(new MigLayout("fill"));

        imageTextField = BasicComponentFactory
                .createTextField(presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_IMAGE));
        imageTextField.setColumns(30);

        chooseImageButton = new JButton("Choose...");
        chooseImageButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                chooseLocoImage();
            }
        });

        imageChoserPanel.add(imageTextField, "grow");
        imageChoserPanel.add(chooseImageButton);

        imageLabel = new JLabel();
        imageLabel.setHorizontalAlignment(SwingConstants.CENTER);

        imageLabel.setIcon(LocomotiveImageHelper.getLocomotiveIcon(presentationModel.getBean()));

        busSpinner = new JSpinner();
        busSpinner.setModel(SpinnerAdapterFactory.createNumberAdapter(
                presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_BUS), 1, // defaultValue
                0, // minValue
                100, // maxValue
                1)); // step

        address1Spinner = new JSpinner();
        address1Spinner.setModel(SpinnerAdapterFactory.createNumberAdapter(
                presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_ADDRESS1), 1, // defaultValue
                0, // minValue
                324, // maxValue
                1)); // step

        address2Spinner = new JSpinner();
        address2Spinner.setModel(SpinnerAdapterFactory.createNumberAdapter(
                presentationModel.getBufferedModel(Locomotive.PROPERTYNAME_ADDRESS2), 1, // defaultValue
                0, // minValue
                324, // maxValue
                1)); // step

        final List<LocomotiveType> locomotiveTypes = Arrays.asList(LocomotiveType.values());

        final ValueModel locomotiveTypeModel = presentationModel
                .getBufferedModel(Locomotive.PROPERTYNAME_LOCOMOTIVE_TYPE);
        locomotiveTypeComboBox = BasicComponentFactory
                .createComboBox(new SelectionInList<LocomotiveType>(locomotiveTypes, locomotiveTypeModel));

        functions = new ArrayListModel<LocomotiveFunction>(presentationModel.getBean().getFunctions());
        functionsTable = new JTable();
        functionsModel = new SelectionInList<LocomotiveFunction>();
        functionsModel.setList(functions);

        functionsTable.setModel(new LocomotiveFunctionTableModel(functionsModel));
        functionsTable.getColumnModel().getColumn(0).setCellRenderer(new CenterRenderer());

        errorPanel = new ErrorPanel();

        validate(presentationModel.getBean(), null);
        presentationModel.getBean().addPropertyChangeListener(this);
        okButton = new JButton(new ApplyChangesAction());
        cancelButton = new JButton(new CancelAction());
    }

    private void buildPanel() {
        initComponents();

        final FormLayout layout = new FormLayout("right:pref, 3dlu, pref:grow, 30dlu, right:pref, 3dlu, pref:grow",
                "p:grow, 3dlu,p:grow, 3dlu,p:grow, 3dlu,p:grow, 3dlu,p:grow, 3dlu,p:grow, 3dlu,p:grow");
        layout.setColumnGroups(new int[][] { { 1, 5 }, { 3, 7 } });
        layout.setRowGroups(new int[][] { { 3, 5, 7, 9 } });

        final PanelBuilder builder = new PanelBuilder(layout);
        builder.setDefaultDialogBorder();
        final CellConstraints cc = new CellConstraints();

        builder.addSeparator("General", cc.xyw(1, 1, 3));

        builder.addLabel("Name", cc.xy(1, 3));
        builder.add(nameTextField, cc.xy(3, 3));

        builder.addLabel("Description", cc.xy(1, 5));
        builder.add(descTextField, cc.xy(3, 5));

        builder.addLabel("Type", cc.xy(1, 7));
        builder.add(locomotiveTypeComboBox, cc.xy(3, 7));

        builder.addLabel("Image", cc.xy(1, 9));
        builder.add(chooseImageButton, cc.xy(3, 9));

        builder.add(imageLabel, cc.xyw(1, 11, 3));

        builder.addSeparator("Interface", cc.xyw(5, 1, 3));

        builder.addLabel("Bus", cc.xy(5, 3));
        builder.add(busSpinner, cc.xy(7, 3));

        builder.addLabel("Address 1", cc.xy(5, 5));
        builder.add(address1Spinner, cc.xy(7, 5));

        builder.addLabel("Address 2", cc.xy(5, 7));
        builder.add(address2Spinner, cc.xy(7, 7));

        builder.add(functionsTable, cc.xywh(5, 9, 3, 3));

        builder.add(errorPanel, cc.xyw(1, 13, 3));

        builder.add(buildButtonBar(), cc.xyw(5, 13, 3));

        // add(builder.getPanel());

        setLayout(new MigLayout());

        add(new JLabel("Name"));
        add(nameTextField, "w 300!");

        add(new JLabel("Bus"), "gap unrelated");
        add(busSpinner, "w 150!, wrap");

        add(new JLabel("Description"));
        add(descTextField, "w 300!");

        add(new JLabel("Address 1"), "gap unrelated");
        add(address1Spinner, "w 150!, wrap");

        add(new JLabel("Type"));
        add(locomotiveTypeComboBox, "w 150!");

        add(new JLabel("Address 2"), "gap unrelated");
        add(address2Spinner, "w 150!, wrap");

        add(new JLabel("Image"));
        add(chooseImageButton, "w 150!");

        add(new JLabel("Functions"), "gap unrelated");
        add(new JScrollPane(functionsTable), "h 200!, w 300!, span 1 2, wrap");

        add(imageLabel, "align center, span 2, wrap");

        add(buildButtonBar(), "span 4, align right");

    }

    private JComponent buildButtonBar() {
        return ButtonBarFactory.buildRightAlignedBar(okButton, cancelButton);
    }

    @Override
    public void propertyChange(final PropertyChangeEvent event) {
        final Locomotive locomotive = presentationModel.getBean();

        if (event.getPropertyName().equals(Locomotive.PROPERTYNAME_LOCOMOTIVE_TYPE)) {
            initializeFunctions(locomotive);

        }

        if (!validate(locomotive, event)) {
            return;
        }
    }

    private void initializeFunctions(final Locomotive locomotive) {

        switch (locomotive.getType()) {
        case DELTA:
            locomotive.setFunctions(LocomotiveFunction.getDeltaFunctions());
            break;
        case DIGITAL:
            locomotive.setFunctions(LocomotiveFunction.getDigitalFunctions());
            break;
        case SIMULATED_MFX:
            locomotive.setFunctions(LocomotiveFunction.getSimulatedMfxFunctions());
            break;
        default:
            break;

        }

    }

    private boolean validate(final Locomotive locomotive, final PropertyChangeEvent event) {

        boolean validate = true;
        if (event == null || event.getPropertyName().equals(Locomotive.PROPERTYNAME_NAME)) {
            if (locomotive.getName() == null || locomotive.getName().equals("")) {
                validate = false;
                nameTextField.setBackground(UIConstants.ERROR_COLOR);
            } else {
                nameTextField.setBackground(UIConstants.DEFAULT_TEXTFIELD_COLOR);
            }
        }
        if (event == null || event.getPropertyName().equals(Locomotive.PROPERTYNAME_BUS)
                || event.getPropertyName().equals(Locomotive.PROPERTYNAME_ADDRESS1)) {
            boolean busValid = true;

            if (locomotive.getBus() == 0) {
                setSpinnerColor(busSpinner, UIConstants.ERROR_COLOR);
                validate = false;
                busValid = false;
            } else {
                setSpinnerColor(busSpinner, UIConstants.DEFAULT_TEXTFIELD_COLOR);
            }

            boolean addressValid = true;

            if (locomotive.getAddress1() == 0 || locomotive.getAddress1() > MMTurnout.MAX_MM_TURNOUT_ADDRESS) {
                setSpinnerColor(address1Spinner, UIConstants.ERROR_COLOR);
                validate = false;
                addressValid = false;
            } else {
                setSpinnerColor(address1Spinner, UIConstants.DEFAULT_TEXTFIELD_COLOR);
            }

            if (busValid && addressValid) {

                final int bus = ((Integer) busSpinner.getValue()).intValue();
                final int address = ((Integer) address1Spinner.getValue()).intValue();
                boolean unique = true;
                for (final Locomotive l : ctx.getLocomotiveManager().getAllLocomotives()) {
                    if (l.getBus() == bus && l.getAddress1() == address && !l.equals(locomotive)) {
                        unique = false;
                    }
                }
                if (!unique) {
                    setSpinnerColor(busSpinner, UIConstants.WARN_COLOR);
                    setSpinnerColor(address1Spinner, UIConstants.WARN_COLOR);
                } else {
                    setSpinnerColor(busSpinner, UIConstants.DEFAULT_TEXTFIELD_COLOR);
                    setSpinnerColor(address1Spinner, UIConstants.DEFAULT_TEXTFIELD_COLOR);
                }
            }
        }

        return validate;
    }

    private void setSpinnerColor(final JSpinner spinner, final Color color) {
        final JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) spinner.getEditor();
        editor.getTextField().setBackground(color);
    }

    public void chooseLocoImage() {
        File previousLocoDir = ctx.getPreviousLocoDir();
        if (previousLocoDir == null) {
            previousLocoDir = new File("locoimages");
        }
        final JFileChooser chooser = new JFileChooser(previousLocoDir);

        final ImagePreviewPanel preview = new ImagePreviewPanel();
        chooser.setAccessory(preview);
        chooser.addPropertyChangeListener(preview);

        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setFileFilter(new FileFilter() {

            @Override
            public String getDescription() {
                return "Image Files";
            }

            @Override
            public boolean accept(final File f) {
                if (f.isDirectory()) {
                    return true;
                }
                if (StringUtils.endsWithAny(f.getName().toLowerCase(), ".png", ".gif", ".bmp", ".jpg")) {
                    return true;
                }
                return false;
            }
        });

        final int ret = chooser.showOpenDialog(LocomotiveConfig.this);
        if (ret == JFileChooser.APPROVE_OPTION) {
            File selectedFile = chooser.getSelectedFile();
            ctx.setPreviousLocoDir(selectedFile.getParentFile());
            presentationModel.getBean().setImage(selectedFile.getName());
            final String image = presentationModel.getBean().getImage();
            presentationModel.getBean()
                    .setImageBase64(LocomotiveImageHelper.getImageBase64(presentationModel.getBean()));
            if (image != null && !image.isEmpty()) {
                imageLabel.setIcon(LocomotiveImageHelper.getLocomotiveIcon(presentationModel.getBean()));
                pack();
            } else {
                imageLabel.setIcon(null);
                pack();
            }
        }
    }

    class CenterRenderer extends DefaultTableCellRenderer {

        protected CenterRenderer() {
            setHorizontalAlignment(JLabel.CENTER);
        }
    }

    class ApplyChangesAction extends AbstractAction {

        public ApplyChangesAction() {
            super("OK", ImageTools.createImageIconFromIconSet("dialog-ok-apply.png"));
        }

        @Override
        public void actionPerformed(final ActionEvent e) {
            trigger.triggerCommit();
            final Locomotive locomotive = presentationModel.getBean();
            ctx.getLocomotiveManager().addLocomotiveManagerListener(new LocomotiveAddListener() {

                @Override
                public void locomotiveAdded(final Locomotive locomotive) {
                    success(ctx.getLocomotiveManager(), locomotive);
                }

                @Override
                public void locomotiveUpdated(final Locomotive locomotive) {
                    success(ctx.getLocomotiveManager(), locomotive);
                }

                private void success(final LocomotiveManager locomotivePersistence, final Locomotive locomotive) {
                    locomotivePersistence.removeLocomotiveManagerListenerInNextEvent(this);

                    LocomotiveConfig.this.setVisible(false);
                }

                @Override
                public void failure(final ManagerException arg0) {
                    errorPanel.setErrorText(arg0.getMessage());
                }

            });
            if (createLocomotive) {
                ctx.getLocomotiveManager().addLocomotiveToGroup(locomotive, selectedLocomotiveGroup);
            } else {
                ctx.getLocomotiveManager().updateLocomotive(locomotive);
            }

        }
    }

    class CancelAction extends AbstractAction {

        public CancelAction() {
            super("Cancel", ImageTools.createImageIconFromIconSet("dialog-cancel.png"));
        }

        @Override
        public void actionPerformed(final ActionEvent e) {
            trigger.triggerFlush();
            LocomotiveConfig.this.setVisible(false);
        }
    }
}