001package jmri.jmrit.operations.setup.gui;
002
003import java.awt.GridBagLayout;
004
005import javax.swing.*;
006
007import jmri.InstanceManager;
008import jmri.jmrit.operations.locations.LocationManager;
009import jmri.jmrit.operations.setup.OperationsSetupXml;
010import jmri.jmrit.operations.setup.Setup;
011import jmri.jmrit.operations.trains.TrainManager;
012import jmri.util.swing.JmriJOptionPane;
013
014/**
015 * Frame for user edit of setup options
016 *
017 * @author Dan Boudreau Copyright (C) 2010, 2011, 2012, 2013, 2015, 2026
018 */
019public class OptionPanel extends OperationsPreferencesPanel {
020
021    // labels
022    // major buttons
023    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
024
025    // radio buttons
026    JRadioButton buildNormal = new JRadioButton(Bundle.getMessage("Normal"));
027    JRadioButton buildAggressive = new JRadioButton(Bundle.getMessage("Aggressive"));
028    JRadioButton buildOnTime = new JRadioButton(Bundle.getMessage("OnTime"));
029
030    // check boxes
031    JCheckBox routerCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRouting"));
032    JCheckBox routerYardCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRoutingYard"));
033    JCheckBox routerStagingCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRoutingStaging"));
034    JCheckBox routerAllTrainsBox = new JCheckBox(Bundle.getMessage("AllTrains"));
035    JCheckBox routerRestrictBox = new JCheckBox(Bundle.getMessage("EnableTrackDestinationRestrictions"));
036
037    JCheckBox valueCheckBox = new JCheckBox(Bundle.getMessage("EnableValue"));
038    JCheckBox rfidCheckBox = new JCheckBox(Bundle.getMessage("EnableRfid"));
039    JCheckBox carLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableCarLogging"));
040    JCheckBox engineLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableEngineLogging"));
041    JCheckBox trainLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableTrainLogging"));
042
043    JCheckBox localInterchangeCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalInterchange"));
044    JCheckBox localSpurCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalSpur"));
045    JCheckBox localYardCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalYard"));
046
047    JCheckBox trainIntoStagingCheckBox = new JCheckBox(Bundle.getMessage("TrainIntoStaging"));
048    JCheckBox stagingAvailCheckBox = new JCheckBox(Bundle.getMessage("StagingAvailable"));
049    JCheckBox stagingTurnCheckBox = new JCheckBox(Bundle.getMessage("AllowCarsToReturn"));
050    JCheckBox promptFromTrackStagingCheckBox = new JCheckBox(Bundle.getMessage("PromptFromStaging"));
051    JCheckBox promptToTrackStagingCheckBox = new JCheckBox(Bundle.getMessage("PromptToStaging"));
052    JCheckBox tryNormalStagingCheckBox = new JCheckBox(Bundle.getMessage("TryNormalStaging"));
053
054    JCheckBox generateCvsManifestCheckBox = new JCheckBox(Bundle.getMessage("GenerateCsvManifest"));
055    JCheckBox generateCvsSwitchListCheckBox = new JCheckBox(Bundle.getMessage("GenerateCsvSwitchList"));
056
057    JCheckBox enableVsdCheckBox = new JCheckBox(Bundle.getMessage("EnableVSD"));
058    JCheckBox saveTrainManifestCheckBox = new JCheckBox(Bundle.getMessage("SaveManifests"));
059
060    // text field
061    JTextField dwellTimeTextField = new JTextField(10);
062    JTextField rfidTextField = new JTextField(10);
063    JTextField valueTextField = new JTextField(10);
064
065    // combo boxes
066    JComboBox<Integer> numberPassesComboBox = new JComboBox<>();
067
068    public OptionPanel() {
069
070        // load checkboxes
071        localInterchangeCheckBox.setSelected(Setup.isLocalInterchangeMovesEnabled());
072        localSpurCheckBox.setSelected(Setup.isLocalSpurMovesEnabled());
073        localYardCheckBox.setSelected(Setup.isLocalYardMovesEnabled());
074        // staging options
075        trainIntoStagingCheckBox.setSelected(Setup.isStagingTrainCheckEnabled());
076        stagingAvailCheckBox.setSelected(Setup.isStagingTrackImmediatelyAvail());
077        stagingTurnCheckBox.setSelected(Setup.isStagingAllowReturnEnabled());
078        promptToTrackStagingCheckBox.setSelected(Setup.isStagingPromptToEnabled());
079        promptFromTrackStagingCheckBox.setSelected(Setup.isStagingPromptFromEnabled());
080        tryNormalStagingCheckBox.setSelected(Setup.isStagingTryNormalBuildEnabled());
081        // router
082        routerCheckBox.setSelected(Setup.isCarRoutingEnabled());
083        routerYardCheckBox.setSelected(Setup.isCarRoutingViaYardsEnabled());
084        routerStagingCheckBox.setSelected(Setup.isCarRoutingViaStagingEnabled());
085        routerAllTrainsBox.setSelected(!Setup.isOnlyActiveTrainsEnabled());
086        routerRestrictBox.setSelected(Setup.isCheckCarDestinationEnabled());
087        // logging options
088        carLoggerCheckBox.setSelected(Setup.isCarLoggerEnabled());
089        engineLoggerCheckBox.setSelected(Setup.isEngineLoggerEnabled());
090        trainLoggerCheckBox.setSelected(Setup.isTrainLoggerEnabled());
091        // save manifests
092        saveTrainManifestCheckBox.setSelected(Setup.isSaveTrainManifestsEnabled());
093
094        generateCvsManifestCheckBox.setSelected(Setup.isGenerateCsvManifestEnabled());
095        generateCvsSwitchListCheckBox.setSelected(Setup.isGenerateCsvSwitchListEnabled());
096        valueCheckBox.setSelected(Setup.isValueEnabled());
097        rfidCheckBox.setSelected(Setup.isRfidEnabled());
098        enableVsdCheckBox.setSelected(Setup.isVsdPhysicalLocationEnabled());
099
100        // load text fields
101        dwellTimeTextField.setText(Integer.toString(Setup.getDwellTime()));
102        rfidTextField.setText(Setup.getRfidLabel());
103        valueTextField.setText(Setup.getValueLabel());
104        
105        // add tool tips
106        saveButton.setToolTipText(Bundle.getMessage("SaveToolTip"));
107        rfidTextField.setToolTipText(Bundle.getMessage("EnterNameRfidTip"));
108        valueTextField.setToolTipText(Bundle.getMessage("EnterNameValueTip"));
109        stagingTurnCheckBox.setToolTipText(Bundle.getMessage("AlsoAvailablePerTrain"));
110
111        // load combobox, allow 2 to 4 passes
112        for (int x = 2; x < 5; x++) {
113            numberPassesComboBox.addItem(x);
114        }
115
116        numberPassesComboBox.setSelectedItem(Setup.getNumberPasses());
117        padComboBox(numberPassesComboBox, 2);
118
119        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
120
121        JPanel panel = new JPanel();
122        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
123        JScrollPane panelPane = new JScrollPane(panel);
124
125        // Build Options panel
126        JPanel pBuild = new JPanel();
127        pBuild.setLayout(new BoxLayout(pBuild, BoxLayout.Y_AXIS));
128        pBuild.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutBuildOptions")));
129
130        JPanel pOpt = new JPanel();
131        pOpt.setLayout(new GridBagLayout());
132
133        addItem(pOpt, buildNormal, 1, 0);
134        addItem(pOpt, buildAggressive, 2, 0);
135        addItem(pOpt, buildOnTime, 3, 0);
136        pBuild.add(pOpt);
137
138        JPanel pPasses = new JPanel();
139        pPasses.setLayout(new GridBagLayout());
140        pPasses.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutNumberPasses")));
141        addItem(pPasses, numberPassesComboBox, 0, 0);
142        pBuild.add(pPasses);
143        
144        JPanel pDwellTime = new JPanel();
145        pDwellTime.setLayout(new GridBagLayout());
146        pDwellTime.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutDwellTime")));
147        addItem(pDwellTime, dwellTimeTextField, 0, 0);
148        pBuild.add(pDwellTime);
149
150        // Switcher Service
151        JPanel pSwitcher = new JPanel();
152        pSwitcher.setLayout(new GridBagLayout());
153        pSwitcher.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutSwitcherService")));
154
155        addItemLeft(pSwitcher, localInterchangeCheckBox, 1, 1);
156        addItemLeft(pSwitcher, localSpurCheckBox, 1, 2);
157        addItemLeft(pSwitcher, localYardCheckBox, 1, 3);
158
159        // Staging
160        JPanel pStaging = new JPanel();
161        pStaging.setLayout(new GridBagLayout());
162        pStaging.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutStaging")));
163
164        addItemLeft(pStaging, trainIntoStagingCheckBox, 1, 4);
165        addItemLeft(pStaging, stagingAvailCheckBox, 1, 5);
166        addItemLeft(pStaging, stagingTurnCheckBox, 1, 6);
167        addItemLeft(pStaging, promptFromTrackStagingCheckBox, 1, 7);
168        addItemLeft(pStaging, promptToTrackStagingCheckBox, 1, 8);
169        addItemLeft(pStaging, tryNormalStagingCheckBox, 1, 9);
170
171        // Router panel
172        JPanel pRouter = new JPanel();
173        pRouter.setLayout(new GridBagLayout());
174        pRouter.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutRouterOptions")));
175        addItemLeft(pRouter, routerCheckBox, 1, 0);
176        addItemLeft(pRouter, routerYardCheckBox, 1, 1);
177        addItemLeft(pRouter, routerStagingCheckBox, 1, 2);
178        addItemLeft(pRouter, routerAllTrainsBox, 1, 3);
179        addItemLeft(pRouter, routerRestrictBox, 1, 4);
180
181        // Logger panel
182        JPanel pLogger = new JPanel();
183        pLogger.setLayout(new GridBagLayout());
184        pLogger.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutLoggerOptions")));
185        addItemLeft(pLogger, engineLoggerCheckBox, 1, 0);
186        addItemLeft(pLogger, carLoggerCheckBox, 1, 1);
187        addItemLeft(pLogger, trainLoggerCheckBox, 1, 2);
188
189        // Custom Manifests and Switch Lists
190        JPanel pCustom = new JPanel();
191        pCustom.setLayout(new GridBagLayout());
192        pCustom.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutCustomManifests")));
193        addItemLeft(pCustom, generateCvsManifestCheckBox, 1, 0);
194        addItemLeft(pCustom, generateCvsSwitchListCheckBox, 1, 1);
195
196        // Options
197        JPanel pOption = new JPanel();
198        pOption.setLayout(new GridBagLayout());
199        pOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptions")));
200        addItemLeft(pOption, saveTrainManifestCheckBox, 1, 1);
201        addItemLeft(pOption, valueCheckBox, 1, 2);
202        addItemLeft(pOption, valueTextField, 2, 2);
203        addItemLeft(pOption, rfidCheckBox, 1, 3);
204        addItemLeft(pOption, rfidTextField, 2, 3);
205        addItemLeft(pOption, enableVsdCheckBox, 1, 4);
206
207        // row 11
208        JPanel pControl = new JPanel();
209        pControl.setLayout(new GridBagLayout());
210        addItem(pControl, saveButton, 3, 9);
211
212        panel.add(pBuild);
213        panel.add(pSwitcher);
214        panel.add(pStaging);
215        panel.add(pRouter);
216        panel.add(pLogger);
217        panel.add(pCustom);
218        panel.add(pOption);
219
220        add(panelPane);
221        add(pControl);
222
223        // setup buttons
224        addButtonAction(saveButton);
225
226        // radio buttons
227        ButtonGroup buildGroup = new ButtonGroup();
228        buildGroup.add(buildNormal);
229        buildGroup.add(buildAggressive);
230        buildGroup.add(buildOnTime);
231        
232        addRadioButtonAction(buildNormal);
233        addRadioButtonAction(buildAggressive);
234        addRadioButtonAction(buildOnTime);
235
236        // check boxes
237        addCheckBoxAction(routerCheckBox);
238        addCheckBoxAction(routerRestrictBox);
239        setRouterCheckBoxesEnabled();
240
241        setBuildOption();
242        enableComponents();
243    }
244
245    private void setBuildOption() {
246        buildNormal.setSelected(!Setup.isBuildAggressive());
247        buildAggressive.setSelected(Setup.isBuildAggressive());
248        buildOnTime.setSelected(Setup.isBuildOnTime());
249    }
250
251    private void enableComponents() {
252        // disable staging option if normal mode
253        stagingAvailCheckBox.setEnabled(!buildNormal.isSelected());
254        numberPassesComboBox.setEnabled(!buildNormal.isSelected());
255        dwellTimeTextField.setEnabled(buildOnTime.isSelected());
256        tryNormalStagingCheckBox.setEnabled(!buildNormal.isSelected());
257    }
258
259    @Override
260    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
261        log.debug("radio button selected");
262        // can't change the build option if there are trains built
263        if (InstanceManager.getDefault(TrainManager.class).isAnyTrainBuilt()) {
264            setBuildOption(); // restore the correct setting
265            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotChangeBuild"),
266                    Bundle.getMessage("MustTerminateOrReset"), JmriJOptionPane.ERROR_MESSAGE);
267        }
268        enableComponents();
269        // Special case where there are train build failures that created work.
270        // Track reserve needs to cleaned up by reseting build failed trains
271        if (buildAggressive.isSelected() != Setup.isBuildAggressive() &&
272                InstanceManager.getDefault(LocationManager.class).hasWork()) {
273            InstanceManager.getDefault(TrainManager.class).resetBuildFailedTrains();
274        }
275    }
276
277    // Save button
278    @Override
279    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
280        if (ae.getSource() == saveButton) {
281            this.savePreferences();
282            var topLevelAncestor = getTopLevelAncestor();
283            if (Setup.isCloseWindowOnSaveEnabled() && topLevelAncestor instanceof OptionFrame) {
284                ((OptionFrame) topLevelAncestor).dispose();
285            }
286        }
287    }
288
289    @Override
290    protected void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
291        if (ae.getSource() == routerCheckBox) {
292            setRouterCheckBoxesEnabled();
293        }
294        if (ae.getSource() == routerRestrictBox && routerRestrictBox.isSelected()) {
295            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("WarnExtremeTrackDest"),
296                    Bundle.getMessage("WarnExtremeTitle"), JmriJOptionPane.WARNING_MESSAGE);
297        }
298    }
299
300    private void setRouterCheckBoxesEnabled() {
301        routerYardCheckBox.setEnabled(routerCheckBox.isSelected());
302        routerStagingCheckBox.setEnabled(routerCheckBox.isSelected());
303        routerAllTrainsBox.setEnabled(routerCheckBox.isSelected());
304        routerRestrictBox.setEnabled(routerCheckBox.isSelected());
305    }
306
307    @Override
308    public String getTabbedPreferencesTitle() {
309        return Bundle.getMessage("TitleOptions");
310    }
311
312    @Override
313    public String getPreferencesTooltip() {
314        return null;
315    }
316
317    @Override
318    public void savePreferences() {
319        // build option
320        Setup.setBuildAggressive(buildAggressive.isSelected() || buildOnTime.isSelected());
321        Setup.setNumberPasses((Integer) numberPassesComboBox.getSelectedItem());
322        Setup.setBuildOnTime(buildOnTime.isSelected());
323        try {
324            Setup.setDwellTime(Integer.parseInt(dwellTimeTextField.getText()));
325        } catch (NumberFormatException e) {
326            log.error("Dwell Time {} must be a number", dwellTimeTextField.getText());
327        }
328        // local switcher options
329        Setup.setLocalInterchangeMovesEnabled(localInterchangeCheckBox.isSelected());
330        Setup.setLocalSpurMovesEnabled(localSpurCheckBox.isSelected());
331        Setup.setLocalYardMovesEnabled(localYardCheckBox.isSelected());
332        // Staging options
333        Setup.setStagingTrainCheckEnabled(trainIntoStagingCheckBox.isSelected());
334        Setup.setStagingTrackImmediatelyAvail(stagingAvailCheckBox.isSelected());
335        Setup.setStagingAllowReturnEnabled(stagingTurnCheckBox.isSelected());
336        Setup.setStagingPromptFromEnabled(promptFromTrackStagingCheckBox.isSelected());
337        Setup.setStagingPromptToEnabled(promptToTrackStagingCheckBox.isSelected());
338        Setup.setStagingTryNormalBuildEnabled(tryNormalStagingCheckBox.isSelected());
339        // Car routing enabled?
340        Setup.setCarRoutingEnabled(routerCheckBox.isSelected());
341        Setup.setCarRoutingViaYardsEnabled(routerYardCheckBox.isSelected());
342        Setup.setCarRoutingViaStagingEnabled(routerStagingCheckBox.isSelected());
343        Setup.setOnlyActiveTrainsEnabled(!routerAllTrainsBox.isSelected());
344        Setup.setCheckCarDestinationEnabled(routerRestrictBox.isSelected());
345        // Options
346        Setup.setGenerateCsvManifestEnabled(generateCvsManifestCheckBox.isSelected());
347        Setup.setGenerateCsvSwitchListEnabled(generateCvsSwitchListCheckBox.isSelected());
348        Setup.setSaveTrainManifestsEnabled(saveTrainManifestCheckBox.isSelected());
349        Setup.setValueEnabled(valueCheckBox.isSelected());
350        Setup.setValueLabel(valueTextField.getText());
351        Setup.setRfidEnabled(rfidCheckBox.isSelected());
352        Setup.setRfidLabel(rfidTextField.getText());
353        // Logging enabled?
354        Setup.setEngineLoggerEnabled(engineLoggerCheckBox.isSelected());
355        Setup.setCarLoggerEnabled(carLoggerCheckBox.isSelected());
356        Setup.setTrainLoggerEnabled(trainLoggerCheckBox.isSelected());
357        // VSD
358        Setup.setVsdPhysicalLocationEnabled(enableVsdCheckBox.isSelected());
359        // write the file
360        InstanceManager.getDefault(OperationsSetupXml.class).writeOperationsFile();
361    }
362
363    @Override
364    public boolean isDirty() {
365        return !( // build option
366        Setup.isBuildAggressive() == buildAggressive.isSelected() &&
367                Setup.getNumberPasses() == (int) numberPassesComboBox.getSelectedItem()
368                // Local moves?
369                &&
370                Setup.isLocalInterchangeMovesEnabled() == localInterchangeCheckBox.isSelected() &&
371                Setup.isLocalSpurMovesEnabled() == localSpurCheckBox.isSelected() &&
372                Setup.isLocalYardMovesEnabled() == localYardCheckBox.isSelected()
373                // Staging options
374                &&
375                Setup.isStagingTrainCheckEnabled() == trainIntoStagingCheckBox.isSelected() &&
376                Setup.isStagingTrackImmediatelyAvail() == stagingAvailCheckBox.isSelected() &&
377                Setup.isStagingAllowReturnEnabled() == stagingTurnCheckBox.isSelected() &&
378                Setup.isStagingPromptFromEnabled() == promptFromTrackStagingCheckBox.isSelected() &&
379                Setup.isStagingPromptToEnabled() == promptToTrackStagingCheckBox.isSelected() &&
380                Setup.isStagingTryNormalBuildEnabled() == tryNormalStagingCheckBox.isSelected()
381                // Car routing enabled?
382                &&
383                Setup.isCarRoutingEnabled() == routerCheckBox.isSelected() &&
384                Setup.isCarRoutingViaYardsEnabled() == routerYardCheckBox.isSelected() &&
385                Setup.isCarRoutingViaStagingEnabled() == routerStagingCheckBox.isSelected() &&
386                Setup.isOnlyActiveTrainsEnabled() == !routerAllTrainsBox.isSelected() &&
387                Setup.isCheckCarDestinationEnabled() == routerRestrictBox.isSelected()
388                // Options
389                &&
390                Setup.isGenerateCsvManifestEnabled() == generateCvsManifestCheckBox.isSelected() &&
391                Setup.isGenerateCsvSwitchListEnabled() == generateCvsSwitchListCheckBox.isSelected() &&
392                Setup.isValueEnabled() == valueCheckBox.isSelected() &&
393                Setup.getValueLabel().equals(valueTextField.getText()) &&
394                Setup.isRfidEnabled() == rfidCheckBox.isSelected() &&
395                Setup.getRfidLabel().equals(rfidTextField.getText()) &&
396                Setup.isSaveTrainManifestsEnabled() == saveTrainManifestCheckBox.isSelected()
397                // Logging enabled?
398                &&
399                Setup.isEngineLoggerEnabled() == engineLoggerCheckBox.isSelected() &&
400                Setup.isCarLoggerEnabled() == carLoggerCheckBox.isSelected() &&
401                Setup.isTrainLoggerEnabled() == trainLoggerCheckBox.isSelected()
402                // VSD
403                &&
404                Setup.isVsdPhysicalLocationEnabled() == enableVsdCheckBox.isSelected());
405    }
406
407    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OptionPanel.class);
408
409}