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