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        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
191        JPanel eCbPanel = new JPanel();
192        exclusiveCB = new JCheckBox(Bundle.getMessage("LabelExclusive"));
193        exclusiveCB.setToolTipText(Bundle.getMessage("ToolTipExclusive"));
194        eCbPanel.add(exclusiveCB);
195        panel.add(eCbPanel);
196
197        // only display hint if silent share option is enabled in main throttle prefs
198        var tm = InstanceManager.getNullableDefault(jmri.ThrottleManager.class);
199        if ( tm != null && tm.enablePrefSilentShareOption() ) {
200            JPanel sscHint = new JPanel();
201            sscHint.add(new JLabel(Bundle.getMessage("LabelStealShare")));
202            panel.add(sscHint);
203        }
204        return panel;
205    }
206
207    private JPanel networkPanel() {
208        JPanel nPanelRow1 = new JPanel();
209        JPanel nPanelRow2 = new JPanel();
210        JPanel nPanelRow3 = new JPanel();
211        JPanel nPanel = new JPanel(new GridLayout(3, 1));
212
213        port = new JSpinner(new SpinnerNumberModel(localPrefs.getPort(), 1, 65535, 1));
214        port.setToolTipText(Bundle.getMessage("PortToolTip"));
215        port.setEditor(new JSpinner.NumberEditor(port, "#"));
216        JLabel label = new JLabel(Bundle.getMessage("LabelPort"));
217        label.setToolTipText(port.getToolTipText());
218        nPanelRow1.add(port);
219        nPanelRow1.add(label);
220        nPanel.add(nPanelRow1);
221
222        startupCB = new JCheckBox(Bundle.getMessage("LabelStartup"), isStartUpAction());
223        startupItemListener = (ItemEvent e) -> {
224            this.startupCB.removeItemListener(this.startupItemListener);
225            StartupActionsManager manager = InstanceManager.getDefault(StartupActionsManager.class);
226            if (this.startupCB.isSelected()) {
227                PerformActionModel model = new PerformActionModel();
228                model.setClassName(WiThrottleCreationAction.class.getName());
229                if (this.startupActionPosition == -1 || this.startupActionPosition >= manager.getActions().length) {
230                    manager.addAction(model);
231                } else {
232                    manager.setActions(this.startupActionPosition, model);
233                }
234            } else {
235                manager.getActions(PerformActionModel.class).stream().filter((model) -> (WiThrottleCreationAction.class.getName().equals(model.getClassName()))).forEach((model) -> {
236                    this.startupActionPosition = Arrays.asList(manager.getActions()).indexOf(model);
237                    manager.removeAction(model);
238                });
239            }
240            this.startupCB.addItemListener(this.startupItemListener);
241        };
242        this.startupCB.addItemListener(this.startupItemListener);
243        nPanelRow2.add(startupCB);
244        nPanel.add(nPanelRow2);
245
246        useIPv4CB = new JCheckBox(Bundle.getMessage("LabelUseIPv4"), isUseIPv4());
247        useIPv4CB.setToolTipText(Bundle.getMessage("ToolTipUseIPv4"));
248        nPanelRow3.add(useIPv4CB);
249        useIPv6CB = new JCheckBox(Bundle.getMessage("LabelUseIPv6"), isUseIPv6());
250        useIPv6CB.setToolTipText(Bundle.getMessage("ToolTipUseIPv6"));
251        nPanelRow3.add(useIPv6CB);
252        nPanel.add(nPanelRow3);
253
254        return nPanel;
255    }
256
257    private JPanel allowedControllers() {
258        JPanel panel = new JPanel();
259
260        powerCB = new JCheckBox(Bundle.getMessage("LabelTrackPower"));
261        powerCB.setToolTipText(Bundle.getMessage("ToolTipTrackPower"));
262
263        turnoutCB = new JCheckBox(Bundle.getMessage("Turnouts"));
264        turnoutCB.setToolTipText(Bundle.getMessage("ToolTipTurnout"));
265
266        turnoutCreationCB = new JCheckBox(Bundle.getMessage("TurnoutCreation"));
267        turnoutCreationCB.setToolTipText(Bundle.getMessage("ToolTipTurnoutCreation"));
268
269        routeCB = new JCheckBox(Bundle.getMessage("LabelRoute"));
270        routeCB.setToolTipText(Bundle.getMessage("ToolTipRoute"));
271
272        fastClockDisplayCB = new JCheckBox(Bundle.getMessage("LabelFastClockDisplayed"));
273        fastClockDisplayCB.setToolTipText(Bundle.getMessage("ToolTipFastClockDisplayed"));
274
275        consistCB = new JCheckBox(Bundle.getMessage("LabelConsist"));
276        consistCB.setToolTipText(Bundle.getMessage("ToolTipConsist"));
277
278        wifiRB = new JRadioButton(Bundle.getMessage("LabelWiFiConsist"));
279        wifiRB.setToolTipText(Bundle.getMessage("ToolTipWiFiConsist"));
280        dccRB = new JRadioButton(Bundle.getMessage("LabelDCCConsist"));
281        dccRB.setToolTipText(Bundle.getMessage("ToolTipDCCConsist"));
282
283        ButtonGroup group = new ButtonGroup();
284        group.add(wifiRB);
285        group.add(dccRB);
286
287        JPanel gridPanel = new JPanel(new GridLayout(0, 2));
288        JPanel conPanel = new JPanel();
289
290        gridPanel.add(powerCB);
291        gridPanel.add(fastClockDisplayCB);
292        gridPanel.add(turnoutCB);
293        gridPanel.add(turnoutCreationCB);
294        gridPanel.add(routeCB);
295
296        conPanel.setLayout(new BoxLayout(conPanel, BoxLayout.Y_AXIS));
297        wifiRB.setMargin(new Insets(0, 20, 0, 0));
298        dccRB.setMargin(new Insets(0, 20, 0, 0));
299        conPanel.add(consistCB);
300        conPanel.add(wifiRB);
301        conPanel.add(dccRB);
302
303        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 40, 0));
304        panel.add(gridPanel);
305        panel.add(conPanel);
306
307        return panel;
308    }
309
310    //private final static Logger log = LoggerFactory.getLogger(WiThrottlePrefsPanel.class);
311    @Override
312    public String getPreferencesItem() {
313        return "WITHROTTLE"; // NOI18N
314    }
315
316    @Override
317    public String getPreferencesItemText() {
318        return Bundle.getMessage("MenuMenu"); // NOI18N
319    }
320
321    @Override
322    public String getTabbedPreferencesTitle() {
323        return getPreferencesItemText();
324    }
325
326    @Override
327    public String getLabelKey() {
328        return null;
329    }
330
331    @Override
332    public JComponent getPreferencesComponent() {
333        return this;
334    }
335
336    @Override
337    public boolean isPersistant() {
338        return false;
339    }
340
341    @Override
342    public String getPreferencesTooltip() {
343        return null;
344    }
345
346    @Override
347    public void savePreferences() {
348        if (setValues()) {
349            this.localPrefs.save();
350        }
351    }
352
353    @Override
354    public boolean isDirty() {
355        return this.localPrefs.isDirty();
356    }
357
358    @Override
359    public boolean isRestartRequired() {
360        return this.localPrefs.isRestartRequired();
361    }
362
363    @Override
364    public boolean isPreferencesValid() {
365        return true; // no validity checking performed
366    }
367
368    private boolean isStartUpAction() {
369        return InstanceManager.getDefault(StartupActionsManager.class).getActions(PerformActionModel.class).stream()
370                .anyMatch((model) -> (WiThrottleCreationAction.class.getName().equals(model.getClassName())));
371    }
372
373    private boolean isUseIPv4() {
374        return InstanceManager.getDefault(ZeroConfServiceManager.class).getPreferences().isUseIPv4();
375    }
376
377    private boolean isUseIPv6() {
378        return InstanceManager.getDefault(ZeroConfServiceManager.class).getPreferences().isUseIPv6();
379    }
380}