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}