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; 027 028/** 029 * New GUI pane for a Virtual Sound Decoder (VSDecoder). 030 * 031 * <hr> 032 * This file is part of JMRI. 033 * <p> 034 * JMRI is free software; you can redistribute it and/or modify it under 035 * the terms of version 2 of the GNU General Public License as published 036 * by the Free Software Foundation. See the "COPYING" file for a copy 037 * of this license. 038 * <p> 039 * JMRI is distributed in the hope that it will be useful, but WITHOUT 040 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 041 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 042 * for more details. 043 * 044 * @author Mark Underwood Copyright (C) 2011 045 */ 046public class VSDControl extends JPanel { 047 048 public static final String OPTION_CHANGE = "OptionChange"; // NOI18N 049 public static final String DELETE = "DeleteDecoder"; // NOI18N 050 051 private static final int NUMBER_SOUNDS = 8; 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 void addSoundButtons(ArrayList<SoundEvent> elist) { 209 soundsPanel.removeAll(); 210 int i = 0; 211 for (SoundEvent e : elist) { 212 if (e.getButton() != null) { 213 log.debug("adding button {}", e.getButton()); 214 JComponent jc = e.getButton(); 215 GridBagConstraints gbc = new GridBagConstraints(); 216 // Force the EngineSoundEvent to the second row. 217 if (e instanceof EngineSoundEvent) { 218 gbc.gridy = 1; 219 if (elist.size() > NUMBER_SOUNDS) { 220 gbc.gridy = 2; // third row 221 } 222 gbc.gridwidth = elist.size() - 1; 223 gbc.fill = GridBagConstraints.NONE; 224 gbc.anchor = GridBagConstraints.LINE_START; 225 soundsPanel.add(jc, gbc); 226 } else { 227 i++; 228 gbc.gridy = 0; 229 if (i > NUMBER_SOUNDS) { 230 gbc.gridy = 1; 231 } 232 soundsPanel.add(jc, gbc); 233 } 234 } 235 } 236 } 237 238 /** 239 * Handle "Option" button presses. 240 * @param e unused. 241 */ 242 protected void optionButtonPressed(ActionEvent e) { 243 log.debug("({}) Option Button Pressed", address); 244 VSDOptionsDialog d = new VSDOptionsDialog(this, Bundle.getMessage("OptionsDialogTitlePrefix") + " " + this.address); 245 d.addPropertyChangeListener(new PropertyChangeListener() { 246 @Override 247 public void propertyChange(PropertyChangeEvent event) { 248 log.debug("property change name: {}, old: {}, new: {}", event.getPropertyName(), event.getOldValue(), event.getNewValue()); 249 optionsDialogPropertyChange(event); 250 } 251 }); 252 } 253 254 /** 255 * Handle "Delete" button presses. 256 * @param e unused. 257 */ 258 protected void deleteButtonPressed(ActionEvent e) { 259 log.debug("({}) Delete Button Pressed", address); 260 firePropertyChange(DELETE, address, null); 261 } 262 263 /** 264 * Callback for the Option Dialog. 265 * @param event the event to get new value from. 266 */ 267 protected void optionsDialogPropertyChange(PropertyChangeEvent event) { 268 log.debug("internal options dialog handler"); 269 firePropertyChange(OPTION_CHANGE, null, event.getNewValue()); 270 } 271 272 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(VSDControl.class); 273 274}