001package jmri.jmrit.dispatcher;
002
003import java.awt.Container;
004import java.awt.FlowLayout;
005import java.awt.event.ActionEvent;
006import java.awt.event.ActionListener;
007import java.util.ArrayList;
008import java.util.Enumeration;
009
010import javax.swing.BorderFactory;
011import javax.swing.BoxLayout;
012import javax.swing.ButtonGroup;
013import javax.swing.JButton;
014import javax.swing.JCheckBox;
015import javax.swing.JCheckBoxMenuItem;
016import javax.swing.JComboBox;
017import javax.swing.JLabel;
018import javax.swing.JMenu;
019import javax.swing.JMenuItem;
020import javax.swing.JPanel;
021import javax.swing.JRadioButton;
022import javax.swing.JSeparator;
023import javax.swing.JSpinner;
024import javax.swing.SpinnerNumberModel;
025
026import jmri.InstanceManager;
027import jmri.Scale;
028import jmri.ScaleManager;
029import jmri.implementation.SignalSpeedMap;
030import jmri.jmrit.dispatcher.DispatcherFrame.TrainsFrom;
031import jmri.jmrit.display.EditorManager;
032import jmri.jmrit.display.layoutEditor.LayoutEditor;
033import jmri.util.JmriJFrame;
034import jmri.util.swing.JmriJOptionPane;
035
036/**
037 * Set up and processes items in the Dispatcher Options menu.
038 *
039 * @author Dave Duchamp Copyright (C) 2008
040 */
041public class OptionsMenu extends JMenu {
042
043    public OptionsMenu(DispatcherFrame f) {
044        dispatcher = f;
045        this.setText(Bundle.getMessage("MenuOptions"));
046        autoDispatchItem = new JCheckBoxMenuItem(Bundle.getMessage("AutoDispatchItem"));
047        this.add(autoDispatchItem);
048        autoDispatchItem.addActionListener(new ActionListener() {
049            @Override
050            public void actionPerformed(ActionEvent event) {
051                handleAutoDispatch(event);
052            }
053        });
054        autoTurnoutsItem = new JCheckBoxMenuItem(Bundle.getMessage("AutoTurnoutsItem"));
055        this.add(autoTurnoutsItem);
056        autoTurnoutsItem.addActionListener(new ActionListener() {
057            @Override
058            public void actionPerformed(ActionEvent event) {
059                handleAutoTurnouts(event);
060            }
061        });
062        JMenuItem optionWindowItem = new JMenuItem(Bundle.getMessage("OptionWindowItem") + "...");
063        this.add(optionWindowItem);
064        optionWindowItem.addActionListener(new ActionListener() {
065            @Override
066            public void actionPerformed(ActionEvent event) {
067                optionWindowRequested(event);
068            }
069        });
070        JMenuItem saveOptionsItem = new JMenuItem(Bundle.getMessage("SaveOptionsItem"));
071        this.add(saveOptionsItem);
072        saveOptionsItem.addActionListener(new ActionListener() {
073            @Override
074            public void actionPerformed(ActionEvent event) {
075                saveRequested(event);
076            }
077        });
078        initializeMenu();
079    }
080
081    protected DispatcherFrame dispatcher = null;
082
083    // Option menu items
084    private JCheckBoxMenuItem autoDispatchItem = null;
085    private JCheckBoxMenuItem autoTurnoutsItem = null;
086
087    // Initialize check box items in menu from Dispatcher
088    public void initializeMenu() {
089        autoDispatchItem.setSelected(dispatcher.getAutoAllocate());
090        autoTurnoutsItem.setSelected(dispatcher.getAutoTurnouts());
091    }
092
093    private void handleAutoDispatch(ActionEvent e) {
094        boolean set = autoDispatchItem.isSelected();
095        dispatcher.setAutoAllocate(set);
096    }
097
098    private void handleAutoTurnouts(ActionEvent e) {
099        boolean set = autoTurnoutsItem.isSelected();
100        dispatcher.setAutoTurnouts(set);
101    }
102
103    // options window items
104    JmriJFrame optionsFrame = null;
105    Container optionsPane = null;
106    JCheckBox useConnectivityCheckBox = new JCheckBox(Bundle.getMessage("UseConnectivity"));
107    ArrayList<LayoutEditor> layoutEditorList = new ArrayList<>();
108
109    JCheckBox autoAllocateCheckBox = new JCheckBox(Bundle.getMessage("AutoAllocateBox"));
110    JCheckBox autoTurnoutsCheckBox = new JCheckBox(Bundle.getMessage("AutoTurnoutsBox"));
111    JRadioButton trainsFromRoster = new JRadioButton(Bundle.getMessage("TrainsFromRoster"));
112    JRadioButton trainsFromTrains = new JRadioButton(Bundle.getMessage("TrainsFromTrains"));
113    JRadioButton trainsFromUser = new JRadioButton(Bundle.getMessage("TrainsFromUser"));
114    JComboBox<String> signalTypeBox;
115    JCheckBox detectionCheckBox = new JCheckBox(Bundle.getMessage("DetectionBox"));
116    JCheckBox setSSLDirectionalSensorsCheckBox = new JCheckBox(Bundle.getMessage("SetSSLDirectionSensorsBox"));
117    JCheckBox shortNameCheckBox = new JCheckBox(Bundle.getMessage("ShortNameBox"));
118    JCheckBox nameInBlockCheckBox = new JCheckBox(Bundle.getMessage("NameInBlockBox"));
119    JCheckBox rosterInBlockCheckBox = new JCheckBox(Bundle.getMessage("RosterInBlockBox"));
120    JCheckBox extraColorForAllocatedCheckBox = new JCheckBox(Bundle.getMessage("ExtraColorForAllocatedBox"));
121    JCheckBox nameInAllocatedBlockCheckBox = new JCheckBox(Bundle.getMessage("NameInAllocatedBlockBox"));
122    JCheckBox supportVSDecoderCheckBox = new JCheckBox(Bundle.getMessage("SupportVSDecoder"));
123    JComboBox<Scale> layoutScaleBox = new JComboBox<>();
124    JRadioButton scaleFeet = new JRadioButton(Bundle.getMessage("ScaleFeet"));
125    JRadioButton scaleMeters = new JRadioButton(Bundle.getMessage("ScaleMeters"));
126    JCheckBox openDispatcherWithPanel = new JCheckBox(Bundle.getMessage("OpenDispatcherWithPanelBox"));
127    JSpinner minThrottleIntervalSpinner = new JSpinner(new SpinnerNumberModel(100, 20, 1000, 1));
128    JSpinner fullRampTimeSpinner = new JSpinner(new SpinnerNumberModel(5000, 1000, 20000, 1));
129    JCheckBox trustKnownTurnoutsCheckBox = new JCheckBox(Bundle.getMessage("trustKnownTurnouts"));
130    JComboBox<String> stoppingSpeedBox = new JComboBox<>();
131
132    String[] signalTypes = {Bundle.getMessage("SignalType1"), Bundle.getMessage("SignalType2"), Bundle.getMessage("SignalType3")};
133
134    private void optionWindowRequested(ActionEvent e) {
135        if (optionsFrame == null) {
136            optionsFrame = new JmriJFrame(Bundle.getMessage("OptionWindowItem"), false, true);
137            optionsFrame.addHelpMenu("package.jmri.jmrit.dispatcher.Options", true);
138            optionsPane = optionsFrame.getContentPane();
139            optionsPane.setLayout(new BoxLayout(optionsFrame.getContentPane(), BoxLayout.Y_AXIS));
140            JPanel p1 = new JPanel();
141            p1.setLayout(new FlowLayout());
142            p1.add(useConnectivityCheckBox);
143            useConnectivityCheckBox.setToolTipText(Bundle.getMessage("UseConnectivityHint"));
144            signalTypeBox = new JComboBox<>(signalTypes);
145            p1.add(signalTypeBox);
146            signalTypeBox.setToolTipText(Bundle.getMessage("SignalTypeHint"));
147            optionsPane.add(p1);
148            JPanel p2 = new JPanel();
149            p2.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsFrom")));
150            p2.setLayout(new FlowLayout());
151            ButtonGroup trainsGroup = new ButtonGroup();
152            p2.add(trainsFromRoster);
153            trainsFromRoster.setToolTipText(Bundle.getMessage("TrainsFromRosterHint"));
154            trainsGroup.add(trainsFromRoster);
155
156            ActionListener useRosterEntryListener = new ActionListener() {
157                @Override
158                public void actionPerformed(ActionEvent e) {
159                    if (trainsFromRoster.isSelected()) {
160                        rosterInBlockCheckBox.setEnabled(true);
161                        if (nameInBlockCheckBox.isSelected() && e.getSource() == nameInBlockCheckBox) {
162                            rosterInBlockCheckBox.setSelected(false);
163                        } else if (rosterInBlockCheckBox.isSelected() && e.getSource() == rosterInBlockCheckBox) {
164                            nameInBlockCheckBox.setSelected(false);
165                        }
166                    } else {
167                        rosterInBlockCheckBox.setEnabled(false);
168                    }
169                }
170            };
171            trainsFromRoster.addActionListener(useRosterEntryListener);
172            p2.add(new JLabel("     "));
173            p2.add(trainsFromTrains);
174            trainsFromTrains.setToolTipText(Bundle.getMessage("TrainsFromTrainsHint"));
175            trainsFromTrains.addActionListener(useRosterEntryListener);
176            trainsGroup.add(trainsFromTrains);
177            p2.add(new JLabel("     "));
178            p2.add(trainsFromUser);
179            trainsFromUser.setToolTipText(Bundle.getMessage("TrainsFromUserHint"));
180            trainsFromUser.addActionListener(useRosterEntryListener);
181            trainsGroup.add(trainsFromUser);
182            optionsPane.add(p2);
183            JPanel p3 = new JPanel();
184            p3.setLayout(new FlowLayout());
185            p3.add(detectionCheckBox);
186            detectionCheckBox.setToolTipText(Bundle.getMessage("DetectionBoxHint"));
187            optionsPane.add(p3);
188            JPanel p3A = new JPanel();
189            p3A.setLayout(new FlowLayout());
190            p3A.add(setSSLDirectionalSensorsCheckBox);
191            setSSLDirectionalSensorsCheckBox.setToolTipText(Bundle.getMessage("SetSSLDirectionSensorsBoxHint"));
192            optionsPane.add(p3A);
193            JPanel p4 = new JPanel();
194            p4.setLayout(new FlowLayout());
195            p4.add(autoAllocateCheckBox);
196            autoAllocateCheckBox.setToolTipText(Bundle.getMessage("AutoAllocateBoxHint"));
197            optionsPane.add(p4);
198            JPanel p5 = new JPanel();
199            p5.setLayout(new FlowLayout());
200            p5.add(autoTurnoutsCheckBox);
201            autoTurnoutsCheckBox.setToolTipText(Bundle.getMessage("AutoTurnoutsBoxHint"));
202            optionsPane.add(p5);
203            JPanel p16 = new JPanel();
204            p16.setLayout(new FlowLayout());
205            p16.add(trustKnownTurnoutsCheckBox);
206            trustKnownTurnoutsCheckBox.setToolTipText(Bundle.getMessage("trustKnownTurnoutsHint"));
207            optionsPane.add(p16);
208            JPanel p6 = new JPanel();
209            p6.setLayout(new FlowLayout());
210            p6.add(shortNameCheckBox);
211            shortNameCheckBox.setToolTipText(Bundle.getMessage("ShortNameBoxHint"));
212            optionsPane.add(p6);
213            JPanel p7 = new JPanel();
214            p7.setLayout(new FlowLayout());
215            p7.add(nameInBlockCheckBox);
216            nameInBlockCheckBox.setToolTipText(Bundle.getMessage("NameInBlockBoxHint"));
217            nameInBlockCheckBox.addActionListener(useRosterEntryListener);
218            optionsPane.add(p7);
219            JPanel p7b = new JPanel();
220            p7b.setLayout(new FlowLayout());
221            p7b.add(rosterInBlockCheckBox);
222            rosterInBlockCheckBox.setToolTipText(Bundle.getMessage("RosterInBlockBoxHint"));
223            rosterInBlockCheckBox.addActionListener(useRosterEntryListener);
224            optionsPane.add(p7b);
225
226            JPanel p10 = new JPanel();
227            p10.setLayout(new FlowLayout());
228            p10.add(extraColorForAllocatedCheckBox);
229            extraColorForAllocatedCheckBox.setToolTipText(Bundle.getMessage("ExtraColorForAllocatedBoxHint"));
230            optionsPane.add(p10);
231            JPanel p11 = new JPanel();
232            p11.setLayout(new FlowLayout());
233            p11.add(nameInAllocatedBlockCheckBox);
234            nameInAllocatedBlockCheckBox.setToolTipText(Bundle.getMessage("NameInAllocatedBlockBoxHint"));
235            optionsPane.add(p11);
236            JPanel p13 = new JPanel();
237            p13.setLayout(new FlowLayout());
238            p13.add(supportVSDecoderCheckBox);
239            supportVSDecoderCheckBox.setToolTipText(Bundle.getMessage("SupportVSDecoderBoxHint"));
240            optionsPane.add(p13);
241            JPanel p8 = new JPanel();
242            initializeScaleCombo();
243            p8.add(new JLabel(Bundle.getMessage("LabelLayoutScale")));
244            p8.add(layoutScaleBox);
245            layoutScaleBox.setToolTipText(Bundle.getMessage("ScaleBoxHint"));
246            optionsPane.add(p8);
247            JPanel p12 = new JPanel();
248            p12.setLayout(new FlowLayout());
249            p12.add(new JLabel(Bundle.getMessage("Units") + "  "));
250            ButtonGroup scaleGroup = new ButtonGroup();
251            p12.add(scaleFeet);
252            scaleFeet.setToolTipText(Bundle.getMessage("ScaleFeetHint"));
253            scaleGroup.add(scaleFeet);
254            p12.add(new JLabel("  "));
255            p12.add(scaleMeters);
256            scaleMeters.setToolTipText(Bundle.getMessage("ScaleMetersHint"));
257            scaleGroup.add(scaleMeters);
258            optionsPane.add(p12);
259
260            JPanel p14 = new JPanel();
261            initializeStoppingSpeedCombo();
262            p14.add(new JLabel(Bundle.getMessage("LabelStoppingSpeed")));
263            p14.add(stoppingSpeedBox);
264            stoppingSpeedBox.setToolTipText(Bundle.getMessage("StoppingSpeedHint"));
265            optionsPane.add(p14);
266
267            JPanel p15 = new JPanel();
268            p15.setLayout(new FlowLayout());
269            p15.add(new JLabel(Bundle.getMessage("minThrottleInterval") + ":"));
270            minThrottleIntervalSpinner.setToolTipText(Bundle.getMessage("minThrottleIntervalHint"));
271            p15.add(minThrottleIntervalSpinner);
272            p15.add(new JLabel(Bundle.getMessage("LabelMilliseconds")));
273            optionsPane.add(p15);
274
275            JPanel p17 = new JPanel();
276            p17.setLayout(new FlowLayout());
277            p17.add(new JLabel(Bundle.getMessage("fullRampTime") + " :"));
278            fullRampTimeSpinner.setToolTipText(Bundle.getMessage("fullRampTimeHint", Bundle.getMessage("RAMP_FAST")));
279            p17.add(fullRampTimeSpinner);
280            p17.add(new JLabel(Bundle.getMessage("LabelMilliseconds")));
281            optionsPane.add(p17);
282
283            JPanel p18 = new JPanel();
284            p18.setLayout(new FlowLayout());
285            p18.add(openDispatcherWithPanel);
286            openDispatcherWithPanel.setToolTipText(Bundle.getMessage("OpenDispatcherWithPanelBoxHint"));
287            optionsPane.add(p18);
288
289            optionsPane.add(new JSeparator());
290            JPanel p9 = new JPanel();
291            p9.setLayout(new FlowLayout());
292            JButton cancelButton = null;
293            p9.add(cancelButton = new JButton(Bundle.getMessage("ButtonCancel")));
294            cancelButton.addActionListener(new ActionListener() {
295                @Override
296                public void actionPerformed(ActionEvent e) {
297                    cancelOptions(e);
298                }
299            });
300            cancelButton.setToolTipText(Bundle.getMessage("CancelButtonHint2"));
301            p9.add(new JLabel("     "));
302            JButton applyButton = null;
303            p9.add(applyButton = new JButton(Bundle.getMessage("ButtonApply")));
304            applyButton.addActionListener(new ActionListener() {
305                @Override
306                public void actionPerformed(ActionEvent e) {
307                    applyOptions(e);
308                }
309            });
310            applyButton.setToolTipText(Bundle.getMessage("ApplyButtonHint"));
311            optionsPane.add(p9);
312        }
313
314        initializeLayoutEditorList();
315        useConnectivityCheckBox.setEnabled(!layoutEditorList.isEmpty());
316        useConnectivityCheckBox.setSelected(dispatcher.getUseConnectivity());
317
318        signalTypeBox.setSelectedIndex(dispatcher.getSignalType());
319        switch (dispatcher.getTrainsFrom()) {
320            case TRAINSFROMROSTER:
321                trainsFromRoster.setSelected(true);
322                break;
323            case TRAINSFROMOPS:
324                trainsFromTrains.setSelected(true);
325                break;
326            case TRAINSFROMUSER:
327            default:
328                trainsFromUser.setSelected(true);
329        }
330        detectionCheckBox.setSelected(dispatcher.getHasOccupancyDetection());
331        setSSLDirectionalSensorsCheckBox.setSelected(dispatcher.getSetSSLDirectionalSensors());
332        autoAllocateCheckBox.setSelected(dispatcher.getAutoAllocate());
333        autoTurnoutsCheckBox.setSelected(dispatcher.getAutoTurnouts());
334        trustKnownTurnoutsCheckBox.setSelected(dispatcher.getTrustKnownTurnouts());
335        shortNameCheckBox.setSelected(dispatcher.getShortActiveTrainNames());
336        nameInBlockCheckBox.setSelected(dispatcher.getShortNameInBlock());
337        rosterInBlockCheckBox.setSelected(dispatcher.getRosterEntryInBlock());
338        extraColorForAllocatedCheckBox.setSelected(dispatcher.getExtraColorForAllocated());
339        nameInAllocatedBlockCheckBox.setSelected(dispatcher.getNameInAllocatedBlock());
340        supportVSDecoderCheckBox.setSelected(dispatcher.getSupportVSDecoder());
341        scaleMeters.setSelected(dispatcher.getUseScaleMeters());
342        scaleFeet.setSelected(!dispatcher.getUseScaleMeters());
343        minThrottleIntervalSpinner.setValue(dispatcher.getMinThrottleInterval());
344        fullRampTimeSpinner.setValue(dispatcher.getFullRampTime());
345
346        boolean openDispatcher = false;
347        for (LayoutEditor panel : layoutEditorList) {
348            if (panel.getOpenDispatcherOnLoad()) {
349                openDispatcher = true;
350            }
351        }
352        openDispatcherWithPanel.setSelected(openDispatcher);
353        openDispatcherWithPanel.setEnabled(!layoutEditorList.isEmpty());
354
355        optionsFrame.pack();
356        optionsFrame.setVisible(true);
357    }
358
359    private void applyOptions(ActionEvent e) {
360        dispatcher.setUseConnectivity(useConnectivityCheckBox.isSelected());
361        dispatcher.setSetSSLDirectionalSensors(setSSLDirectionalSensorsCheckBox.isSelected());
362        if (trainsFromRoster.isSelected()) {
363            dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER);
364        } else if (trainsFromTrains.isSelected()) {
365            dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMOPS);
366        } else {
367            dispatcher.setTrainsFrom(TrainsFrom.TRAINSFROMUSER);
368        }
369        dispatcher.setHasOccupancyDetection(detectionCheckBox.isSelected());
370        dispatcher.setAutoAllocate(autoAllocateCheckBox.isSelected());
371        autoDispatchItem.setSelected(autoAllocateCheckBox.isSelected());
372        dispatcher.setAutoTurnouts(autoTurnoutsCheckBox.isSelected());
373        autoTurnoutsItem.setSelected(autoTurnoutsCheckBox.isSelected());
374        dispatcher.setTrustKnownTurnouts(trustKnownTurnoutsCheckBox.isSelected());
375        dispatcher.setSignalType(signalTypeBox.getSelectedIndex());
376        if (autoTurnoutsCheckBox.isSelected() && ((layoutEditorList.size() == 0)
377                || (!useConnectivityCheckBox.isSelected()))) {
378            JmriJOptionPane.showMessageDialog(optionsFrame, Bundle.getMessage(
379                    "AutoTurnoutsWarn"), Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE);
380        }
381        dispatcher.setShortActiveTrainNames(shortNameCheckBox.isSelected());
382        dispatcher.setShortNameInBlock(nameInBlockCheckBox.isSelected());
383        dispatcher.setExtraColorForAllocated(extraColorForAllocatedCheckBox.isSelected());
384        dispatcher.setNameInAllocatedBlock(nameInAllocatedBlockCheckBox.isSelected());
385        dispatcher.setRosterEntryInBlock(rosterInBlockCheckBox.isSelected());
386        dispatcher.setSupportVSDecoder(supportVSDecoderCheckBox.isSelected());
387        dispatcher.setScale((Scale) layoutScaleBox.getSelectedItem());
388        dispatcher.setUseScaleMeters(scaleMeters.isSelected());
389        dispatcher.setMinThrottleInterval((int) minThrottleIntervalSpinner.getValue());
390        dispatcher.setFullRampTime((int) fullRampTimeSpinner.getValue());
391
392        for (LayoutEditor panel : layoutEditorList) {
393            panel.setOpenDispatcherOnLoad(openDispatcherWithPanel.isSelected());
394        }
395
396        dispatcher.setStoppingSpeedName( (String) stoppingSpeedBox.getSelectedItem());
397        optionsFrame.setVisible(false);
398        optionsFrame.dispose(); // prevent this window from being listed in the Window menu.
399        optionsFrame = null;
400        // display save options reminder
401        InstanceManager.getDefault(jmri.UserPreferencesManager.class).
402                showInfoMessage(Bundle.getMessage("ReminderTitle"), Bundle.getMessage("ReminderSaveOptions"),
403                        OptionsMenu.class.getName(),
404                        "remindSaveDispatcherOptions"); // NOI18N
405        initializeMenu();
406    }
407
408    private void cancelOptions(ActionEvent e) {
409        optionsFrame.setVisible(false);
410        optionsFrame.dispose(); // prevent this window from being listed in the Window menu.
411        optionsFrame = null;
412    }
413
414    /**
415     * Save Dispatcher Option settings from pane to xml file.
416     *
417     * @param e the calling actionevent
418     */
419    private void saveRequested(ActionEvent e) {
420        try {
421            InstanceManager.getDefault(OptionsFile.class).writeDispatcherOptions(dispatcher);
422        } catch (java.io.IOException ioe) {
423            log.error("Exception writing Dispatcher options", ioe);
424        }
425    }
426
427    private void initializeLayoutEditorList() {
428        // get list of Layout Editor panels
429        layoutEditorList = new ArrayList<>(InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class));
430    }
431
432    private void initializeScaleCombo() {
433        layoutScaleBox.removeAllItems();
434        for (Scale scale : ScaleManager.getScales()) {
435            if (scale.getScaleName().equals("CUSTOM")) {  // No custom support yet, don't show.
436                continue;
437            }
438            layoutScaleBox.addItem(scale);
439        }
440        jmri.util.swing.JComboBoxUtil.setupComboBoxMaxRows(layoutScaleBox);
441        layoutScaleBox.setSelectedItem(dispatcher.getScale());
442    }
443
444    private void initializeStoppingSpeedCombo() {
445        stoppingSpeedBox.removeAllItems();
446        Enumeration<String> speedNamesList = jmri.InstanceManager.getDefault(SignalSpeedMap.class).getSpeedIterator();
447        while (speedNamesList.hasMoreElements()) {
448            stoppingSpeedBox.addItem(speedNamesList.nextElement());
449        }
450        stoppingSpeedBox.setSelectedItem(dispatcher.getStoppingSpeedName());
451    }
452
453    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OptionsMenu.class);
454
455}