001package jmri.jmrix.openlcb.swing.protocoloptions; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006import java.awt.Container; 007import java.awt.GridBagConstraints; 008import java.awt.GridBagLayout; 009import java.awt.Insets; 010import java.awt.event.WindowEvent; 011import java.util.ArrayList; 012import java.util.HashMap; 013import java.util.List; 014import java.util.Map; 015import java.util.MissingResourceException; 016 017import javax.swing.BoxLayout; 018import javax.swing.ImageIcon; 019import javax.swing.JButton; 020import javax.swing.JComboBox; 021import javax.swing.JLabel; 022import javax.swing.JPanel; 023import javax.swing.JTabbedPane; 024import javax.swing.JTextField; 025 026import jmri.jmrix.can.CanSystemConnectionMemo; 027import jmri.util.FileUtil; 028import jmri.util.JmriJFrame; 029import static jmri.jmrix.openlcb.OlcbConfigurationManager.*; 030 031 032/** 033 * JmriFrame that allows the user to edit the OpenLCB protocol options. 034 * 035 * @author Balazs Racz, (C) 2018. 036 */ 037 038public class ProtocolOptionsFrame extends JmriJFrame { 039 final CanSystemConnectionMemo scm; 040 041 public ProtocolOptionsFrame(CanSystemConnectionMemo scm) { 042 super(); 043 this.scm = scm; 044 } 045 046 private final Map<String, JPanel> protocolPanels = new HashMap<>(); 047 private JTabbedPane protocolTabs; 048 private final List<Runnable> saveCallbacks = new ArrayList<>(); 049 boolean anyChanged = false; 050 051 private JPanel getProtocolTab(String protocolKey) { 052 JPanel p = protocolPanels.get(protocolKey); 053 if (p != null) return p; 054 055 p = new JPanel(new GridBagLayout()); 056 p.setName(Bundle.getMessage("TabTitle" + protocolKey)); 057 protocolTabs.add(p); 058 protocolPanels.put(protocolKey, p); 059 060 // We create a first row with empty panels in order to ensure that the relative placement 061 // choices later make sense. 062 GridBagConstraints c1 = new GridBagConstraints(); 063 c1.gridx = 0; 064 c1.gridy = 0; 065 p.add(new JPanel(), c1); 066 067 GridBagConstraints c2 = new GridBagConstraints(); 068 c2.gridx = 1; 069 c2.gridy = 0; 070 p.add(new JPanel(), c2); 071 072 return p; 073 } 074 075 private void addTextSetting(final String protocolKey, final String optionKey) { 076 String pastValue = scm.getProtocolOption(protocolKey, optionKey); 077 if (pastValue == null) pastValue = ""; 078 JPanel tab = getProtocolTab(protocolKey); 079 080 addOptionLabel(protocolKey, optionKey, tab); 081 082 final JTextField valueField = new JTextField(pastValue, 20); 083 GridBagConstraints c2 = new GridBagConstraints(); 084 c2.gridy = GridBagConstraints.RELATIVE; 085 c2.gridx = 1; 086 c2.anchor = GridBagConstraints.FIRST_LINE_START; 087 c2.insets = new Insets(0, 0, 0, 3); 088 089 tab.add(valueField, c2); 090 091 try { 092 String tip = Bundle.getMessage("ToolTip" + protocolKey + optionKey); 093 valueField.setToolTipText(tip); 094 } catch (MissingResourceException e) { 095 // Ignore: no tool tip if bundle does not have it. 096 } 097 098 saveCallbacks.add(() -> { 099 String v = scm.getProtocolOption(protocolKey, optionKey); 100 String newV = valueField.getText(); 101 if (newV.equals(v)) return; 102 scm.setProtocolOption(protocolKey, optionKey, newV); 103 anyChanged = true; 104 }); 105 valueField.addActionListener(actionEvent -> log.warn("Entry changed: {} {} = {}", protocolKey, optionKey, valueField.getText())); 106 } 107 108 private void addOptionLabel(String protocolKey, String optionKey, JPanel tab) { 109 String labelText = Bundle.getMessage("Label" + protocolKey + optionKey); 110 111 JLabel label = new JLabel(labelText); 112 GridBagConstraints c1 = new GridBagConstraints(); 113 c1.gridy = GridBagConstraints.RELATIVE; 114 c1.gridx = 0; 115 c1.anchor = GridBagConstraints.FIRST_LINE_END; 116 c1.insets = new Insets(0, 0, 0, 3); 117 118 tab.add(label, c1); 119 } 120 121 private static class ComboSelectionEntry { 122 final String displayKey; 123 final String selectionKey; 124 125 private ComboSelectionEntry(String displayKey, String selectionKey) { 126 this.displayKey = displayKey; 127 this.selectionKey = selectionKey; 128 } 129 130 @Override 131 public String toString() { 132 return displayKey; 133 } 134 } 135 136 private void addComboBoxSetting(String protocolKey, String optionKey, String[] choices, String defaultChoice) { 137 JPanel tab = getProtocolTab(protocolKey); 138 String pastValue = scm.getProtocolOption(protocolKey, optionKey); 139 140 141 addOptionLabel(protocolKey, optionKey, tab); 142 143 final JComboBox<ComboSelectionEntry> valueField = new JComboBox<>(); 144 int defaultNum = -1; 145 int pastNum = -1; 146 for (int i = 0; i < choices.length; ++i) { 147 if (choices[i].equals(pastValue)) { 148 pastNum = i; 149 } 150 if (choices[i].equals(defaultChoice)) { 151 defaultNum = i; 152 } 153 String displayKey; 154 try { 155 displayKey = Bundle.getMessage("Selection" + protocolKey + optionKey + choices[i]); 156 157 } catch (MissingResourceException e) { 158 displayKey = choices[i]; 159 } 160 valueField.addItem(new ComboSelectionEntry(displayKey, choices[i])); 161 } 162 if (pastNum >= 0) { 163 valueField.setSelectedIndex(pastNum); 164 } else if (pastValue == null) { 165 valueField.setSelectedIndex(defaultNum); 166 } 167 168 GridBagConstraints c2 = new GridBagConstraints(); 169 c2.gridy = GridBagConstraints.RELATIVE; 170 c2.gridx = 1; 171 c2.anchor = GridBagConstraints.FIRST_LINE_START; 172 c2.insets = new Insets(0, 0, 0, 3); 173 174 tab.add(valueField, c2); 175 176 try { 177 String tip = Bundle.getMessage("ToolTip" + protocolKey + optionKey); 178 valueField.setToolTipText(tip); 179 } catch (MissingResourceException e) { 180 // Ignore: no tool tip if bundle does not have it. 181 } 182 183 saveCallbacks.add(() -> { 184 String v = scm.getProtocolOption(protocolKey, optionKey); 185 ComboSelectionEntry newO = (ComboSelectionEntry) valueField.getSelectedItem(); 186 if (newO == null) return; 187 String newV = newO.selectionKey; 188 if (newV.equals(v)) return; 189 scm.setProtocolOption(protocolKey, optionKey, newV); 190 anyChanged = true; 191 }); 192 } 193 194 @Override 195 public void initComponents() { 196 setTitle(Bundle.getMessage("WindowTitle", scm.getUserName())); 197 198 Container contentPane = getContentPane(); 199 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 200 201 protocolTabs = new JTabbedPane(); 202 contentPane.add(protocolTabs); 203 204 getProtocolTab(OPT_PROTOCOL_IDENT); 205 addTextSetting(OPT_PROTOCOL_IDENT, OPT_IDENT_NODEID); 206 addTextSetting(OPT_PROTOCOL_IDENT, OPT_IDENT_USERNAME); 207 addTextSetting(OPT_PROTOCOL_IDENT, OPT_IDENT_DESCRIPTION); 208 209 getProtocolTab(OPT_PROTOCOL_FASTCLOCK); 210 addComboBoxSetting(OPT_PROTOCOL_FASTCLOCK, OPT_FASTCLOCK_ENABLE, new String[] {OPT_FASTCLOCK_ENABLE_OFF, OPT_FASTCLOCK_ENABLE_GENERATOR, OPT_FASTCLOCK_ENABLE_CONSUMER}, OPT_FASTCLOCK_ENABLE_OFF); 211 addComboBoxSetting(OPT_PROTOCOL_FASTCLOCK, OPT_FASTCLOCK_ID, new String[]{OPT_FASTCLOCK_ID_DEFAULT, OPT_FASTCLOCK_ID_DEFAULT_RT, OPT_FASTCLOCK_ID_ALT_1, OPT_FASTCLOCK_ID_ALT_2, OPT_FASTCLOCK_ID_CUSTOM}, OPT_FASTCLOCK_ID_DEFAULT); 212 addTextSetting(OPT_PROTOCOL_FASTCLOCK, OPT_FASTCLOCK_CUSTOM_ID); 213 214 JPanel helpHintPanel = new JPanel(); 215 BoxLayout helpLayout = new BoxLayout(helpHintPanel, BoxLayout.X_AXIS); 216 helpHintPanel.setLayout(helpLayout); 217 contentPane.add(helpHintPanel); 218 JLabel hintOnHelpLabel = new JLabel(Bundle.getMessage("HintOnHelp")); 219 helpHintPanel.add(hintOnHelpLabel); 220 221 JPanel bottomPanel = new JPanel(); 222 BoxLayout bottomLayout = new BoxLayout(bottomPanel, BoxLayout.X_AXIS); 223 bottomPanel.setLayout(bottomLayout); 224 contentPane.add(bottomPanel); 225 226 JButton saveButton = new JButton( 227 Bundle.getMessage("ButtonSave"), 228 new ImageIcon(FileUtil.findURL("program:resources/icons/misc/gui3/SaveIcon.png", 229 FileUtil.Location.INSTALLED))); 230 bottomPanel.add(saveButton); 231 saveButton.addActionListener(actionEvent -> saveButtonClicked()); 232 233 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 234 bottomPanel.add(cancelButton); 235 cancelButton.addActionListener(actionEvent -> ProtocolOptionsFrame.this.dispatchEvent(new WindowEvent(ProtocolOptionsFrame 236 .this, WindowEvent.WINDOW_CLOSING))); 237 238 pack(); 239 } 240 241 private void saveButtonClicked() { 242 for (Runnable r : saveCallbacks) { 243 r.run(); 244 } 245 this.setVisible(false); 246 this.dispose(); 247 } 248 249 private final static Logger log = LoggerFactory.getLogger(ProtocolOptionsFrame.class); 250}