001package jmri.jmrit.withrottle;
002
003import jmri.util.startup.PerformActionModel;
004import jmri.util.startup.StartupActionsManager;
005
006import java.awt.FlowLayout;
007import java.awt.GridLayout;
008import java.awt.Insets;
009import java.awt.event.ItemEvent;
010import java.awt.event.ItemListener;
011import java.beans.PropertyChangeEvent;
012import java.io.File;
013import java.util.Arrays;
014
015import javax.swing.BoxLayout;
016import javax.swing.ButtonGroup;
017import javax.swing.JCheckBox;
018import javax.swing.JComponent;
019import javax.swing.JLabel;
020import javax.swing.JPanel;
021import javax.swing.JRadioButton;
022import javax.swing.JSpinner;
023import javax.swing.SpinnerNumberModel;
024
025import jmri.InstanceManager;
026import jmri.swing.JTitledSeparator;
027import jmri.swing.PreferencesPanel;
028import jmri.util.FileUtil;
029import jmri.util.swing.JmriJOptionPane;
030import jmri.util.zeroconf.ZeroConfPreferences;
031import jmri.util.zeroconf.ZeroConfServiceManager;
032
033import org.openide.util.lookup.ServiceProvider;
034
035/**
036 * @author Brett Hoffman Copyright (C) 2010
037 */
038@ServiceProvider(service = PreferencesPanel.class)
039public class WiThrottlePrefsPanel extends JPanel implements PreferencesPanel {
040
041    JCheckBox eStopCB;
042    JSpinner delaySpinner;
043
044    JCheckBox momF2CB;
045    
046    JCheckBox exclusiveCB;
047
048    JSpinner port;
049
050    JCheckBox powerCB;
051    JCheckBox turnoutCB;
052    JCheckBox turnoutCreationCB;
053    JCheckBox routeCB;
054    JCheckBox consistCB;
055    JCheckBox startupCB;
056    JCheckBox useIPv4CB;
057    JCheckBox useIPv6CB;
058    JCheckBox fastClockDisplayCB;
059    ItemListener startupItemListener;
060    int startupActionPosition = -1;
061    JRadioButton wifiRB;
062    JRadioButton dccRB;
063
064    //early defaults while creating panel
065    int eStopInitialValue = 10;
066    int eStopMinValue = 4;
067    int eStopMaxValue = 180;
068    int eStopStepSize = 2;
069
070    WiThrottlePreferences localPrefs;
071
072    public WiThrottlePrefsPanel() {
073        if (InstanceManager.getNullableDefault(WiThrottlePreferences.class) == null) {
074            InstanceManager.store(new WiThrottlePreferences(FileUtil.getUserFilesPath() + "throttle" + File.separator + "WiThrottlePreferences.xml"), WiThrottlePreferences.class);
075        }
076        localPrefs = InstanceManager.getDefault(WiThrottlePreferences.class);
077        initGUI();
078        setGUI();
079    }
080
081    public void initGUI() {
082        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
083        add(new JTitledSeparator(Bundle.getMessage("TitleDelayPanel")));
084        add(eStopDelayPanel());
085        add(new JTitledSeparator(Bundle.getMessage("TitleFunctionsPanel")));
086        add(functionsPanel());
087        add(new JTitledSeparator(Bundle.getMessage("TitleExclusivePanel")));
088        add(exclusivePanel());
089        add(new JTitledSeparator(Bundle.getMessage("TitleNetworkPanel")));
090        add(networkPanel());
091        add(new JTitledSeparator(Bundle.getMessage("TitleControllersPanel")));
092        add(allowedControllers());
093    }
094
095    private void setGUI() {
096        eStopCB.setSelected(localPrefs.isUseEStop());
097        delaySpinner.setValue(localPrefs.getEStopDelay());
098
099        momF2CB.setSelected(localPrefs.isUseMomF2());
100        
101        exclusiveCB.setSelected(localPrefs.isExclusiveUseOfAddress());
102
103        port.setValue(localPrefs.getPort());
104        powerCB.setSelected(localPrefs.isAllowTrackPower());
105        turnoutCB.setSelected(localPrefs.isAllowTurnout());
106        turnoutCreationCB.setSelected(localPrefs.isAllowTurnoutCreation());
107        routeCB.setSelected(localPrefs.isAllowRoute());
108        fastClockDisplayCB.setSelected(localPrefs.isDisplayFastClock());
109        consistCB.setSelected(localPrefs.isAllowConsist());
110        InstanceManager.getDefault(StartupActionsManager.class).addPropertyChangeListener((PropertyChangeEvent evt) -> {
111            startupCB.setSelected(isStartUpAction());
112        });
113        useIPv4CB.setSelected(isUseIPv4());
114        useIPv6CB.setSelected(isUseIPv6());
115        wifiRB.setSelected(localPrefs.isUseWiFiConsist());
116        dccRB.setSelected(!localPrefs.isUseWiFiConsist());
117    }
118
119    /**
120     * set the local prefs to match the GUI Local prefs are independent from the
121     * singleton instance prefs.
122     *
123     * @return true if set, false if values are unacceptable.
124     */
125    private boolean setValues() {
126        boolean didSet = true;
127        localPrefs.setUseEStop(eStopCB.isSelected());
128        localPrefs.setEStopDelay((Integer) delaySpinner.getValue());
129
130        localPrefs.setUseMomF2(momF2CB.isSelected());
131        
132        localPrefs.setExclusiveUseOfAddress(exclusiveCB.isSelected());
133
134        int portNum;
135        try {
136            portNum = (int) port.getValue();
137        } catch (NumberFormatException NFE) { //  Not a number
138            portNum = 0;
139        }
140        if ((portNum < 1) || (portNum > 65535)) { //  Invalid port value
141            JmriJOptionPane.showMessageDialog(this,
142                    Bundle.getMessage("WarningInvalidPort"),
143                    Bundle.getMessage("TitlePortWarningDialog"),
144                    JmriJOptionPane.WARNING_MESSAGE);
145            didSet = false;
146        } else {
147            localPrefs.setPort((int) port.getValue());
148        }
149
150        localPrefs.setAllowTrackPower(powerCB.isSelected());
151        localPrefs.setAllowTurnout(turnoutCB.isSelected());
152        localPrefs.setAllowTurnoutCreation(turnoutCreationCB.isSelected());
153        localPrefs.setAllowRoute(routeCB.isSelected());
154        localPrefs.setDisplayFastClock(fastClockDisplayCB.isSelected());
155        localPrefs.setAllowConsist(consistCB.isSelected());
156        localPrefs.setUseWiFiConsist(wifiRB.isSelected());
157        ZeroConfPreferences zeroConfPrefs = InstanceManager.getDefault(ZeroConfServiceManager.class).getPreferences();
158        zeroConfPrefs.setUseIPv4(useIPv4CB.isSelected());
159        zeroConfPrefs.setUseIPv6(useIPv6CB.isSelected());
160
161        return didSet;
162    }
163
164    private JPanel eStopDelayPanel() {
165        JPanel panel = new JPanel();
166
167        eStopCB = new JCheckBox(Bundle.getMessage("LabelUseEStop"));
168        eStopCB.setToolTipText(Bundle.getMessage("ToolTipUseEStop"));
169        SpinnerNumberModel spinMod = new SpinnerNumberModel(eStopInitialValue, eStopMinValue, eStopMaxValue, eStopStepSize);
170        delaySpinner = new JSpinner(spinMod);
171        ((JSpinner.DefaultEditor) delaySpinner.getEditor()).getTextField().setEditable(false);
172        panel.add(eStopCB);
173        panel.add(delaySpinner);
174        panel.add(new JLabel(Bundle.getMessage("LabelEStopDelay")));
175        return panel;
176    }
177
178    private JPanel functionsPanel() {
179        JPanel panel = new JPanel();
180
181        momF2CB = new JCheckBox(Bundle.getMessage("LabelMomF2"));
182        momF2CB.setToolTipText(Bundle.getMessage("ToolTipMomF2"));
183        panel.add(momF2CB);
184        return panel;
185    }
186
187    private JPanel exclusivePanel() {
188        JPanel panel = new JPanel();
189
190        exclusiveCB = new JCheckBox(Bundle.getMessage("LabelExclusive"));
191        exclusiveCB.setToolTipText(Bundle.getMessage("ToolTipExclusive"));
192        panel.add(exclusiveCB);
193        return panel;
194    }
195    
196    private JPanel networkPanel() {
197        JPanel nPanelRow1 = new JPanel();
198        JPanel nPanelRow2 = new JPanel();
199        JPanel nPanelRow3 = new JPanel();
200        JPanel nPanel = new JPanel(new GridLayout(3, 1));
201
202        port = new JSpinner(new SpinnerNumberModel(localPrefs.getPort(), 1, 65535, 1));
203        port.setToolTipText(Bundle.getMessage("PortToolTip"));
204        port.setEditor(new JSpinner.NumberEditor(port, "#"));
205        JLabel label = new JLabel(Bundle.getMessage("LabelPort"));
206        label.setToolTipText(port.getToolTipText());
207        nPanelRow1.add(port);
208        nPanelRow1.add(label);
209        nPanel.add(nPanelRow1);
210
211        startupCB = new JCheckBox(Bundle.getMessage("LabelStartup"), isStartUpAction());
212        startupItemListener = (ItemEvent e) -> {
213            this.startupCB.removeItemListener(this.startupItemListener);
214            StartupActionsManager manager = InstanceManager.getDefault(StartupActionsManager.class);
215            if (this.startupCB.isSelected()) {
216                PerformActionModel model = new PerformActionModel();
217                model.setClassName(WiThrottleCreationAction.class.getName());
218                if (this.startupActionPosition == -1 || this.startupActionPosition >= manager.getActions().length) {
219                    manager.addAction(model);
220                } else {
221                    manager.setActions(this.startupActionPosition, model);
222                }
223            } else {
224                manager.getActions(PerformActionModel.class).stream().filter((model) -> (WiThrottleCreationAction.class.getName().equals(model.getClassName()))).forEach((model) -> {
225                    this.startupActionPosition = Arrays.asList(manager.getActions()).indexOf(model);
226                    manager.removeAction(model);
227                });
228            }
229            this.startupCB.addItemListener(this.startupItemListener);
230        };
231        this.startupCB.addItemListener(this.startupItemListener);
232        nPanelRow2.add(startupCB);
233        nPanel.add(nPanelRow2);
234
235        useIPv4CB = new JCheckBox(Bundle.getMessage("LabelUseIPv4"), isUseIPv4());
236        useIPv4CB.setToolTipText(Bundle.getMessage("ToolTipUseIPv4"));
237        nPanelRow3.add(useIPv4CB);
238        useIPv6CB = new JCheckBox(Bundle.getMessage("LabelUseIPv6"), isUseIPv6());
239        useIPv6CB.setToolTipText(Bundle.getMessage("ToolTipUseIPv6"));
240        nPanelRow3.add(useIPv6CB);
241        nPanel.add(nPanelRow3);
242
243        return nPanel;
244    }
245
246    private JPanel allowedControllers() {
247        JPanel panel = new JPanel();
248
249        powerCB = new JCheckBox(Bundle.getMessage("LabelTrackPower"));
250        powerCB.setToolTipText(Bundle.getMessage("ToolTipTrackPower"));
251
252        turnoutCB = new JCheckBox(Bundle.getMessage("Turnouts"));
253        turnoutCB.setToolTipText(Bundle.getMessage("ToolTipTurnout"));
254
255        turnoutCreationCB = new JCheckBox(Bundle.getMessage("TurnoutCreation"));
256        turnoutCreationCB.setToolTipText(Bundle.getMessage("ToolTipTurnoutCreation"));
257
258        routeCB = new JCheckBox(Bundle.getMessage("LabelRoute"));
259        routeCB.setToolTipText(Bundle.getMessage("ToolTipRoute"));
260
261        fastClockDisplayCB = new JCheckBox(Bundle.getMessage("LabelFastClockDisplayed"));
262        fastClockDisplayCB.setToolTipText(Bundle.getMessage("ToolTipFastClockDisplayed"));
263
264        consistCB = new JCheckBox(Bundle.getMessage("LabelConsist"));
265        consistCB.setToolTipText(Bundle.getMessage("ToolTipConsist"));
266
267        wifiRB = new JRadioButton(Bundle.getMessage("LabelWiFiConsist"));
268        wifiRB.setToolTipText(Bundle.getMessage("ToolTipWiFiConsist"));
269        dccRB = new JRadioButton(Bundle.getMessage("LabelDCCConsist"));
270        dccRB.setToolTipText(Bundle.getMessage("ToolTipDCCConsist"));
271
272        ButtonGroup group = new ButtonGroup();
273        group.add(wifiRB);
274        group.add(dccRB);
275
276        JPanel gridPanel = new JPanel(new GridLayout(0, 2));
277        JPanel conPanel = new JPanel();
278
279        gridPanel.add(powerCB);
280        gridPanel.add(fastClockDisplayCB);
281        gridPanel.add(turnoutCB);
282        gridPanel.add(turnoutCreationCB);
283        gridPanel.add(routeCB);
284
285        conPanel.setLayout(new BoxLayout(conPanel, BoxLayout.Y_AXIS));
286        wifiRB.setMargin(new Insets(0, 20, 0, 0));
287        dccRB.setMargin(new Insets(0, 20, 0, 0));
288        conPanel.add(consistCB);
289        conPanel.add(wifiRB);
290        conPanel.add(dccRB);
291
292        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 40, 0));
293        panel.add(gridPanel);
294        panel.add(conPanel);
295
296        return panel;
297    }
298
299    //private final static Logger log = LoggerFactory.getLogger(WiThrottlePrefsPanel.class);
300    @Override
301    public String getPreferencesItem() {
302        return "WITHROTTLE"; // NOI18N
303    }
304
305    @Override
306    public String getPreferencesItemText() {
307        return Bundle.getMessage("MenuMenu"); // NOI18N
308    }
309
310    @Override
311    public String getTabbedPreferencesTitle() {
312        return getPreferencesItemText();
313    }
314
315    @Override
316    public String getLabelKey() {
317        return null;
318    }
319
320    @Override
321    public JComponent getPreferencesComponent() {
322        return this;
323    }
324
325    @Override
326    public boolean isPersistant() {
327        return false;
328    }
329
330    @Override
331    public String getPreferencesTooltip() {
332        return null;
333    }
334
335    @Override
336    public void savePreferences() {
337        if (setValues()) {
338            this.localPrefs.save();
339        }
340    }
341
342    @Override
343    public boolean isDirty() {
344        return this.localPrefs.isDirty();
345    }
346
347    @Override
348    public boolean isRestartRequired() {
349        return this.localPrefs.isRestartRequired();
350    }
351
352    @Override
353    public boolean isPreferencesValid() {
354        return true; // no validity checking performed
355    }
356
357    private boolean isStartUpAction() {
358        return InstanceManager.getDefault(StartupActionsManager.class).getActions(PerformActionModel.class).stream()
359                .anyMatch((model) -> (WiThrottleCreationAction.class.getName().equals(model.getClassName())));
360    }
361
362    private boolean isUseIPv4() {
363        return InstanceManager.getDefault(ZeroConfServiceManager.class).getPreferences().isUseIPv4();
364    }
365
366    private boolean isUseIPv6() {
367        return InstanceManager.getDefault(ZeroConfServiceManager.class).getPreferences().isUseIPv6();
368    }
369}