001package jmri.jmrit.vsdecoder.swing;
002
003import java.awt.BorderLayout;
004import java.awt.GridBagConstraints;
005import java.awt.GridBagLayout;
006import java.awt.Insets;
007import java.awt.event.ActionEvent;
008import java.awt.event.ActionListener;
009import java.awt.event.KeyEvent;
010import java.beans.PropertyChangeEvent;
011import java.beans.PropertyChangeListener;
012import java.util.ArrayList;
013import java.util.HashMap;
014import java.util.Map;
015import javax.swing.BorderFactory;
016import javax.swing.Box;
017import javax.swing.BoxLayout;
018import javax.swing.JButton;
019import javax.swing.JComponent;
020import javax.swing.JLabel;
021import javax.swing.JPanel;
022import javax.swing.SwingConstants;
023import javax.swing.border.Border;
024import jmri.jmrit.vsdecoder.EngineSoundEvent;
025import jmri.jmrit.vsdecoder.SoundEvent;
026import jmri.jmrit.vsdecoder.VSDConfig;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030/**
031 * New GUI pane for a Virtual Sound Decoder (VSDecoder).
032 *
033 * <hr>
034 * This file is part of JMRI.
035 * <p>
036 * JMRI is free software; you can redistribute it and/or modify it under
037 * the terms of version 2 of the GNU General Public License as published
038 * by the Free Software Foundation. See the "COPYING" file for a copy
039 * of this license.
040 * <p>
041 * JMRI is distributed in the hope that it will be useful, but WITHOUT
042 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
043 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
044 * for more details.
045 *
046 * @author Mark Underwood Copyright (C) 2011
047 */
048public class VSDControl extends JPanel {
049
050    public static final String OPTION_CHANGE = "OptionChange"; // NOI18N
051    public static final String DELETE = "DeleteDecoder"; // NOI18N
052
053    // Map of Mnemonic KeyEvent values to GUI Components
054    private static final Map<String, Integer> Mnemonics = new HashMap<>();
055
056    static {
057        // GUI buttons
058        Mnemonics.put("OptionButton", KeyEvent.VK_O);
059        Mnemonics.put("DeleteButton", KeyEvent.VK_D);
060    }
061
062    String address;
063
064    Border tb;
065    JLabel addressLabel;
066    JButton optionButton;
067    JButton deleteButton;
068
069    JPanel soundsPanel;
070    JPanel configPanel;
071
072    private VSDConfig config;
073
074    /**
075     * Constructor
076     */
077    public VSDControl() {
078        super();
079        initComponents("");
080    }
081
082    /**
083     * Constructor
084     *
085     * @param title (String) : Window title
086     */
087    public VSDControl(String title) {
088        super();
089        address = title;
090        config = new VSDConfig();
091        initComponents(title);
092    }
093
094    public VSDControl(VSDConfig c) {
095        super();
096        config = c;
097        address = config.getLocoAddress().toString();
098        initComponents(address);
099    }
100
101    static public JPanel generateBlank() {
102        VSDControl temp = new VSDControl("");
103        JLabel jl = new JLabel(Bundle.getMessage("BlankVSDControlLabel"));
104        jl.setMinimumSize(temp.getPreferredSize());
105        jl.setPreferredSize(temp.getPreferredSize());
106        jl.setHorizontalAlignment(SwingConstants.CENTER);
107        JPanel jp = new JPanel();
108        jp.setLayout(new BorderLayout());
109        jp.add(jl, BorderLayout.CENTER);
110        jl.setMinimumSize(temp.getPreferredSize());
111        jp.setPreferredSize(temp.getPreferredSize());
112        jp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
113                BorderFactory.createLoweredBevelBorder()));
114        return jp;
115    }
116
117    private GridBagConstraints setConstraints(int x, int y) {
118        return setConstraints(x, y, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), GridBagConstraints.LINE_START);
119    }
120
121    /*
122     private GridBagConstraints setConstraints(int x, int y, int fill) {
123         return setConstraints(x, y, fill, new Insets(2,2,2,2), GridBagConstraints.LINE_START);
124     }
125     */
126
127    private GridBagConstraints setConstraints(int x, int y, int fill, Insets ins, int anchor) {
128        GridBagConstraints gbc1 = new GridBagConstraints();
129        gbc1.insets = ins;
130        gbc1.gridx = x;
131        gbc1.gridy = y;
132        gbc1.weightx = 100.0;
133        gbc1.weighty = 100.0;
134        gbc1.gridwidth = 1;
135        gbc1.anchor = anchor;
136        gbc1.fill = fill;
137
138        return gbc1;
139    }
140
141    /**
142     * Initialize the GUI components.
143     * @param title future title, not yet coded..
144     */
145    protected void initComponents(String title) {
146        // Create the border.
147        // Could make this a titled border with the loco address as the title...
148        //tb = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
149        tb = BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
150                BorderFactory.createLoweredBevelBorder());
151
152        this.setBorder(tb);
153
154        this.setLayout(new GridBagLayout());
155
156        // Create the buttons and slider
157        soundsPanel = new JPanel();
158        soundsPanel.setLayout(new GridBagLayout());
159        addressLabel = new JLabel(address);
160
161        configPanel = new JPanel();
162        configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.PAGE_AXIS));
163        optionButton = new JButton(Bundle.getMessage("OptionsButtonLabel"));
164        deleteButton = new JButton(Bundle.getMessage("ButtonDelete"));
165        configPanel.add(Box.createHorizontalGlue());
166        configPanel.add(optionButton);
167        optionButton.setToolTipText(Bundle.getMessage("MgrOptionButtonToolTip"));
168        optionButton.setMnemonic(Mnemonics.get("OptionButton"));
169        configPanel.add(Box.createHorizontalGlue());
170        configPanel.add(deleteButton);
171        deleteButton.setToolTipText(Bundle.getMessage("MgrDeleteButtonToolTip"));
172        deleteButton.setMnemonic(Mnemonics.get("DeleteButton"));
173
174        JPanel alPanel = new JPanel();
175        alPanel.setLayout(new BoxLayout(alPanel, BoxLayout.PAGE_AXIS));
176        alPanel.add(addressLabel);
177        alPanel.add(new JLabel(config.getProfileName()));
178
179        // Add them to the panel
180        this.add(alPanel, new GridBagConstraints(0, 0, 1, 2, 100.0, 100.0,
181                GridBagConstraints.LINE_START,
182                GridBagConstraints.NONE,
183                new Insets(2, 2, 2, 2),
184                0, 0));
185        this.add(soundsPanel, setConstraints(2, 0));
186        this.add(configPanel, setConstraints(3, 0));
187
188        optionButton.addActionListener(new ActionListener() {
189            @Override
190            public void actionPerformed(ActionEvent e) {
191                optionButtonPressed(e);
192            }
193        });
194        deleteButton.addActionListener(new ActionListener() {
195            @Override
196            public void actionPerformed(ActionEvent e) {
197                deleteButtonPressed(e);
198            }
199        });
200
201        this.setVisible(true);
202    }
203
204    /**
205     * Add buttons for the selected Profile's defined sounds
206     * @param elist list of sounds to make buttons from.
207     */
208    public void addSoundButtons(ArrayList<SoundEvent> elist) {
209        soundsPanel.removeAll();
210        for (SoundEvent e : elist) {
211            if (e.getButton() != null) {
212                log.debug("adding button {}", e.getButton());
213                JComponent jc = e.getButton();
214                GridBagConstraints gbc = new GridBagConstraints();
215                // Force the EngineSoundEvent to the second row.
216                if (e instanceof EngineSoundEvent) {
217                    gbc.gridy = 1;
218                    gbc.gridwidth = elist.size() - 1;
219                    gbc.fill = GridBagConstraints.NONE;
220                    gbc.anchor = GridBagConstraints.LINE_START;
221                    soundsPanel.add(jc, gbc);
222                } else {
223                    gbc.gridy = 0;
224                    soundsPanel.add(jc, gbc);
225                }
226            }
227        }
228    }
229
230    /**
231     * Handle "Option" button presses.
232     * @param e unused.
233     */
234    protected void optionButtonPressed(ActionEvent e) {
235        log.debug("({}) Option Button Pressed", address);
236        VSDOptionsDialog d = new VSDOptionsDialog(this, Bundle.getMessage("OptionsDialogTitlePrefix") + " " + this.address);
237        d.addPropertyChangeListener(new PropertyChangeListener() {
238            @Override
239            public void propertyChange(PropertyChangeEvent event) {
240                log.debug("property change name: {}, old: {}, new: {}", event.getPropertyName(), event.getOldValue(), event.getNewValue());
241                optionsDialogPropertyChange(event);
242            }
243        });
244    }
245
246    /**
247     * Handle "Delete" button presses.
248     * @param e unused.
249     */
250    protected void deleteButtonPressed(ActionEvent e) {
251        log.debug("({}) Delete Button Pressed", address);
252        firePropertyChange(DELETE, address, null);
253    }
254
255    /**
256     * Callback for the Option Dialog.
257     * @param event the event to get new value from.
258     */
259    protected void optionsDialogPropertyChange(PropertyChangeEvent event) {
260        log.debug("internal options dialog handler");
261        firePropertyChange(OPTION_CHANGE, null, event.getNewValue());
262    }
263
264    private static final Logger log = LoggerFactory.getLogger(VSDControl.class);
265
266}