001package jmri.jmrit.dispatcher; 002 003import java.awt.BorderLayout; 004import java.awt.Component; 005import java.awt.Container; 006import java.awt.Dimension; 007import java.awt.FlowLayout; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.awt.event.ItemEvent; 011import java.awt.event.ItemListener; 012import java.util.ArrayList; 013import java.util.HashSet; 014import java.util.List; 015import java.util.Set; 016 017import javax.swing.BorderFactory; 018import javax.swing.BoxLayout; 019import javax.swing.ButtonGroup; 020import javax.swing.JButton; 021import javax.swing.JCheckBox; 022import javax.swing.JComboBox; 023import javax.swing.JLabel; 024import javax.swing.JPanel; 025import javax.swing.JRadioButton; 026import javax.swing.JScrollPane; 027import javax.swing.JSeparator; 028import javax.swing.JSpinner; 029import javax.swing.JTextField; 030import javax.swing.ScrollPaneConstants; 031import javax.swing.SpinnerNumberModel; 032import javax.swing.event.ChangeEvent; 033import javax.swing.event.ChangeListener; 034import javax.swing.table.DefaultTableModel; 035import javax.swing.table.TableCellRenderer; 036import javax.swing.table.TableColumnModel; 037 038import jmri.Block; 039import jmri.InstanceManager; 040import jmri.Sensor; 041import jmri.Transit; 042import jmri.TransitManager; 043import jmri.jmrit.dispatcher.ActiveTrain.TrainDetection; 044import jmri.jmrit.dispatcher.ActiveTrain.TrainLengthUnits; 045import jmri.jmrit.dispatcher.DispatcherFrame.TrainsFrom; 046import jmri.jmrit.operations.trains.Train; 047import jmri.jmrit.operations.trains.TrainManager; 048import jmri.jmrit.roster.RosterEntry; 049import jmri.jmrit.roster.swing.RosterEntryComboBox; 050import jmri.swing.NamedBeanComboBox; 051import jmri.util.JmriJFrame; 052import jmri.util.swing.JComboBoxUtil; 053import jmri.util.swing.JmriJOptionPane; 054import javax.swing.JTable; 055/** 056 * Displays the Activate New Train dialog and processes information entered 057 * there. 058 * <p> 059 * This module works with Dispatcher, which initiates the display of the dialog. 060 * Dispatcher also creates the ActiveTrain. 061 * <p> 062 * This file is part of JMRI. 063 * <p> 064 * JMRI is open source software; you can redistribute it and/or modify it under 065 * the terms of version 2 of the GNU General Public License as published by the 066 * Free Software Foundation. See the "COPYING" file for a copy of this license. 067 * <p> 068 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 069 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 070 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 071 * 072 * @author Dave Duchamp Copyright (C) 2009 073 */ 074public class ActivateTrainFrame extends JmriJFrame { 075 076 public ActivateTrainFrame(DispatcherFrame d) { 077 super(true,true); 078 _dispatcher = d; 079 _tiFile = new TrainInfoFile(); 080 } 081 082 // operational instance variables 083 private DispatcherFrame _dispatcher = null; 084 private TrainInfoFile _tiFile = null; 085 private final TransitManager _TransitManager = InstanceManager.getDefault(jmri.TransitManager.class); 086 private String _trainInfoName = ""; 087 088 // initiate train window variables 089 private Transit selectedTransit = null; 090 //private String selectedTrain = ""; 091 private JmriJFrame initiateFrame = null; 092 private Container initiatePane = null; 093 private final jmri.swing.NamedBeanComboBox<Transit> transitSelectBox = new jmri.swing.NamedBeanComboBox<>(_TransitManager); 094 private final JLabel trainBoxLabel = new JLabel(" " + Bundle.getMessage("TrainBoxLabel") + ":"); 095 private final JComboBox<Object> trainSelectBox = new JComboBox<>(); 096 // private final List<RosterEntry> trainBoxList = new ArrayList<>(); 097 private RosterEntryComboBox rosterComboBox = null; 098 private final JLabel trainFieldLabel = new JLabel(Bundle.getMessage("TrainBoxLabel") + ":"); 099 private final JTextField trainNameField = new JTextField(10); 100 private final JLabel dccAddressFieldLabel = new JLabel(" " + Bundle.getMessage("DccAddressFieldLabel") + ":"); 101 private final JSpinner dccAddressSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 9999, 1)); 102 private final JCheckBox inTransitBox = new JCheckBox(Bundle.getMessage("TrainInTransit")); 103 private final JComboBox<String> startingBlockBox = new JComboBox<>(); 104 private List<Block> startingBlockBoxList = new ArrayList<>(); 105 private List<Integer> startingBlockSeqList = new ArrayList<>(); 106 private final JComboBox<String> destinationBlockBox = new JComboBox<>(); 107 private List<Block> destinationBlockBoxList = new ArrayList<>(); 108 private List<Integer> destinationBlockSeqList = new ArrayList<>(); 109 private JButton addNewTrainButton = null; 110 private JButton loadButton = null; 111 private JButton saveButton = null; 112 private JButton saveAsTemplateButton = null; 113 private JButton deleteButton = null; 114 private final JCheckBox autoRunBox = new JCheckBox(Bundle.getMessage("AutoRun")); 115 private final JCheckBox loadAtStartupBox = new JCheckBox(Bundle.getMessage("LoadAtStartup")); 116 117 private final JRadioButton radioTrainsFromRoster = new JRadioButton(Bundle.getMessage("TrainsFromRoster")); 118 private final JRadioButton radioTrainsFromOps = new JRadioButton(Bundle.getMessage("TrainsFromTrains")); 119 private final JRadioButton radioTrainsFromUser = new JRadioButton(Bundle.getMessage("TrainsFromUser")); 120 private final JRadioButton radioTrainsFromSetLater = new JRadioButton(Bundle.getMessage("TrainsFromSetLater")); 121 private final ButtonGroup trainsFromButtonGroup = new ButtonGroup(); 122 123 private final JRadioButton allocateBySafeRadioButton = new JRadioButton(Bundle.getMessage("ToSafeSections")); 124 private final JRadioButton allocateAllTheWayRadioButton = new JRadioButton(Bundle.getMessage("AsFarAsPos")); 125 private final JRadioButton allocateNumberOfBlocks = new JRadioButton(Bundle.getMessage("NumberOfBlocks") + ":"); 126 private final ButtonGroup allocateMethodButtonGroup = new ButtonGroup(); 127 private final JSpinner allocateCustomSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 100, 1)); 128 private final JCheckBox terminateWhenDoneBox = new JCheckBox(Bundle.getMessage("TerminateWhenDone")); 129 private final JPanel terminateWhenDoneDetails = new JPanel(); 130 private final JComboBox<String> nextTrain = new JComboBox<>(); 131 private final JLabel nextTrainLabel = new JLabel(Bundle.getMessage("TerminateWhenDoneNextTrain")); 132 private final JSpinner prioritySpinner = new JSpinner(new SpinnerNumberModel(5, 0, 100, 1)); 133 private final JCheckBox resetWhenDoneBox = new JCheckBox(Bundle.getMessage("ResetWhenDone")); 134 private final JCheckBox reverseAtEndBox = new JCheckBox(Bundle.getMessage("ReverseAtEnd")); 135 136 int delayedStartInt[] = new int[]{ActiveTrain.NODELAY, ActiveTrain.TIMEDDELAY, ActiveTrain.SENSORDELAY}; 137 String delayedStartString[] = new String[]{Bundle.getMessage("DelayedStartNone"), Bundle.getMessage("DelayedStartTimed"), Bundle.getMessage("DelayedStartSensor")}; 138 139 private final JComboBox<String> reverseDelayedRestartType = new JComboBox<>(delayedStartString); 140 private final JLabel delayReverseReStartLabel = new JLabel(Bundle.getMessage("DelayRestart")); 141 private final JLabel delayReverseReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor")); 142 private final JCheckBox delayReverseResetSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor")); 143 private final NamedBeanComboBox<Sensor> delayReverseReStartSensor = new NamedBeanComboBox<>(jmri.InstanceManager.sensorManagerInstance()); 144 private final JSpinner delayReverseMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); 145 private final JLabel delayReverseMinLabel = new JLabel(Bundle.getMessage("RestartTimed")); 146 147 private final JCheckBox resetStartSensorBox = new JCheckBox(Bundle.getMessage("ResetStartSensor")); 148 private final JComboBox<String> delayedStartBox = new JComboBox<>(delayedStartString); 149 private final JLabel delayedReStartLabel = new JLabel(Bundle.getMessage("DelayRestart")); 150 private final JLabel delayReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor")); 151 private final JCheckBox resetRestartSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor")); 152 private final JComboBox<String> delayedReStartBox = new JComboBox<>(delayedStartString); 153 private final NamedBeanComboBox<Sensor> delaySensor = new NamedBeanComboBox<>(jmri.InstanceManager.sensorManagerInstance()); 154 private final NamedBeanComboBox<Sensor> delayReStartSensor = new NamedBeanComboBox<>(jmri.InstanceManager.sensorManagerInstance()); 155 156 private final JSpinner departureHrSpinner = new JSpinner(new SpinnerNumberModel(8, 0, 23, 1)); 157 private final JSpinner departureMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 59, 1)); 158 private final JLabel departureTimeLabel = new JLabel(Bundle.getMessage("DepartureTime")); 159 private final JLabel departureSepLabel = new JLabel(":"); 160 161 private final JSpinner delayMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); 162 private final JLabel delayMinLabel = new JLabel(Bundle.getMessage("RestartTimed")); 163 164 private final JComboBox<String> trainTypeBox = new JComboBox<>(); 165 // Note: See also items related to automatically running trains near the end of this module 166 167 boolean transitsFromSpecificBlock = false; 168 169 private TrainInfo trainInfo; 170 171 private final String nameOfTemplateFile="TrainInfoDefaultTemplate.xml"; 172 173 /** 174 * Open up a new train window for a given roster entry located in a specific 175 * block. 176 * 177 * @param e the action event triggering the new window 178 * @param re the roster entry to open the new window for 179 * @param b the block where the train is located 180 */ 181 public void initiateTrain(ActionEvent e, RosterEntry re, Block b) { 182 initiateTrain(e); 183 if (trainInfo.getTrainsFrom() == TrainsFrom.TRAINSFROMROSTER && re != null) { 184 setRosterComboBox(rosterComboBox, re.getId()); 185 //Add in some bits of code as some point to filter down the transits that can be used. 186 } 187 if (b != null && selectedTransit != null) { 188 List<Transit> transitList = _TransitManager.getListUsingBlock(b); 189 List<Transit> transitEntryList = _TransitManager.getListEntryBlock(b); 190 for (Transit t : transitEntryList) { 191 if (!transitList.contains(t)) { 192 transitList.add(t); 193 } 194 } 195 transitsFromSpecificBlock = true; 196 initializeFreeTransitsCombo(transitList); 197 List<Block> tmpBlkList = new ArrayList<>(); 198 if (selectedTransit.getEntryBlocksList().contains(b)) { 199 tmpBlkList = selectedTransit.getEntryBlocksList(); 200 inTransitBox.setSelected(false); 201 } else if (selectedTransit.containsBlock(b)) { 202 tmpBlkList = selectedTransit.getInternalBlocksList(); 203 inTransitBox.setSelected(true); 204 } 205 List<Integer> tmpSeqList = selectedTransit.getBlockSeqList(); 206 for (int i = 0; i < tmpBlkList.size(); i++) { 207 if (tmpBlkList.get(i) == b) { 208 setComboBox(startingBlockBox, getBlockName(b) + "-" + tmpSeqList.get(i)); 209 break; 210 } 211 } 212 } 213 } 214 215 /** 216 * Displays a window that allows a new ActiveTrain to be activated. 217 * <p> 218 * Called by Dispatcher in response to the dispatcher clicking the New Train 219 * button. 220 * 221 * @param e the action event triggering the window display 222 */ 223 protected void initiateTrain(ActionEvent e) { 224 // set Dispatcher defaults 225 // create window if needed 226 // if template exists open it 227 try { 228 trainInfo = _tiFile.readTrainInfo(nameOfTemplateFile); 229 if (trainInfo == null) { 230 trainInfo = new TrainInfo(); 231 } 232 } catch (java.io.IOException ioe) { 233 log.error("IO Exception when reading train info file", ioe); 234 return; 235 } catch (org.jdom2.JDOMException jde) { 236 log.error("JDOM Exception when reading train info file", jde); 237 return; 238 } 239 trainInfo.setTrainsFrom(_dispatcher.getTrainsFrom()); 240 241 if (initiateFrame == null) { 242 initiateFrame = this; 243 initiateFrame.setTitle(Bundle.getMessage("AddTrainTitle")); 244 initiateFrame.addHelpMenu("package.jmri.jmrit.dispatcher.NewTrain", true); 245 initiatePane = initiateFrame.getContentPane(); 246 initiatePane.setLayout(new BoxLayout(initiatePane, BoxLayout.Y_AXIS)); 247 248 // add buttons to load and save train information 249 JPanel p0 = new JPanel(); 250 p0.setLayout(new FlowLayout()); 251 p0.add(loadButton = new JButton(Bundle.getMessage("LoadButton"))); 252 loadButton.addActionListener(new ActionListener() { 253 @Override 254 public void actionPerformed(ActionEvent e) { 255 loadTrainInfo(e); 256 } 257 }); 258 loadButton.setToolTipText(Bundle.getMessage("LoadButtonHint")); 259 p0.add(saveButton = new JButton(Bundle.getMessage("SaveButton"))); 260 saveButton.addActionListener(new ActionListener() { 261 @Override 262 public void actionPerformed(ActionEvent e) { 263 saveTrainInfo(e); 264 } 265 }); 266 saveButton.setToolTipText(Bundle.getMessage("SaveButtonHint")); 267 p0.add(saveAsTemplateButton = new JButton(Bundle.getMessage("SaveAsTemplateButton"))); 268 saveAsTemplateButton.addActionListener(new ActionListener() { 269 @Override 270 public void actionPerformed(ActionEvent e) { 271 saveTrainInfoAsTemplate(e); 272 } 273 }); 274 saveAsTemplateButton.setToolTipText(Bundle.getMessage("SaveAsTemplateButtonHint")); 275 p0.add(deleteButton = new JButton(Bundle.getMessage("DeleteButton"))); 276 deleteButton.addActionListener(new ActionListener() { 277 @Override 278 public void actionPerformed(ActionEvent e) { 279 deleteTrainInfo(e); 280 } 281 }); 282 deleteButton.setToolTipText(Bundle.getMessage("DeleteButtonHint")); 283 284 // add items relating to both manually run and automatic trains. 285 286 // Trains From choices. 287 JPanel p0a = new JPanel(); 288 p0a.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsFrom"))); 289 p0a.setLayout(new FlowLayout()); 290 radioTrainsFromRoster.setActionCommand("TRAINSFROMROSTER"); 291 trainsFromButtonGroup.add(radioTrainsFromRoster); 292 radioTrainsFromOps.setActionCommand("TRAINSFROMOPS"); 293 trainsFromButtonGroup.add(radioTrainsFromOps); 294 radioTrainsFromUser.setActionCommand("TRAINSFROMUSER"); 295 trainsFromButtonGroup.add(radioTrainsFromUser); 296 radioTrainsFromSetLater.setActionCommand("TRAINSFROMSETLATER"); 297 trainsFromButtonGroup.add(radioTrainsFromSetLater); 298 p0a.add(radioTrainsFromRoster); 299 radioTrainsFromRoster.setToolTipText(Bundle.getMessage("TrainsFromRosterHint")); 300 p0a.add(radioTrainsFromOps); 301 radioTrainsFromOps.setToolTipText(Bundle.getMessage("TrainsFromTrainsHint")); 302 p0a.add(radioTrainsFromUser); 303 radioTrainsFromUser.setToolTipText(Bundle.getMessage("TrainsFromUserHint")); 304 p0a.add(radioTrainsFromSetLater); 305 radioTrainsFromSetLater.setToolTipText(Bundle.getMessage("TrainsFromSetLaterHint")); 306 307 radioTrainsFromOps.addItemListener(new ItemListener() { 308 @Override 309 public void itemStateChanged(ItemEvent e) { 310 if (e.getStateChange() == ItemEvent.SELECTED) { 311 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMOPS); 312 setTrainsFromOptions(trainInfo.getTrainsFrom()); 313 } 314 } 315 }); 316 317 radioTrainsFromRoster.addItemListener(new ItemListener() { 318 @Override 319 public void itemStateChanged(ItemEvent e) { 320 if (e.getStateChange() == ItemEvent.SELECTED) { 321 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER); 322 setTrainsFromOptions(trainInfo.getTrainsFrom()); 323 } 324 } 325 }); 326 radioTrainsFromUser.addItemListener(new ItemListener() { 327 @Override 328 public void itemStateChanged(ItemEvent e) { 329 if (e.getStateChange() == ItemEvent.SELECTED) { 330 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER); 331 setTrainsFromOptions(trainInfo.getTrainsFrom()); 332 } 333 } 334 }); 335 radioTrainsFromSetLater.addItemListener(new ItemListener() { 336 @Override 337 public void itemStateChanged(ItemEvent e) { 338 if (e.getStateChange() == ItemEvent.SELECTED) { 339 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMSETLATER); 340 setTrainsFromOptions(trainInfo.getTrainsFrom()); 341 } 342 } 343 }); 344 p0a.add(allocateCustomSpinner); 345 initiatePane.add(p0a); 346 347 JPanel p1 = new JPanel(); 348 p1.setLayout(new FlowLayout()); 349 p1.add(new JLabel(Bundle.getMessage("TransitBoxLabel") + " :")); 350 p1.add(transitSelectBox); 351 transitSelectBox.addActionListener(new ActionListener() { 352 @Override 353 public void actionPerformed(ActionEvent e) { 354 handleTransitSelectionChanged(e); 355 } 356 }); 357 transitSelectBox.setToolTipText(Bundle.getMessage("TransitBoxHint")); 358 p1.add(trainBoxLabel); 359 p1.add(trainSelectBox); 360 trainSelectBox.addActionListener(new ActionListener() { 361 @Override 362 public void actionPerformed(ActionEvent e) { 363 handleTrainSelectionChanged(); 364 } 365 }); 366 trainSelectBox.setToolTipText(Bundle.getMessage("TrainBoxHint")); 367 368 rosterComboBox = new RosterEntryComboBox(); 369 initializeFreeRosterEntriesCombo(); 370 rosterComboBox.addActionListener(new ActionListener() { 371 @Override 372 public void actionPerformed(ActionEvent e) { 373 handleRosterSelectionChanged(e); 374 } 375 }); 376 p1.add(rosterComboBox); 377 378 initiatePane.add(p1); 379 JPanel p1a = new JPanel(); 380 p1a.setLayout(new FlowLayout()); 381 p1a.add(trainFieldLabel); 382 p1a.add(trainNameField); 383 trainNameField.setToolTipText(Bundle.getMessage("TrainFieldHint")); 384 p1a.add(dccAddressFieldLabel); 385 p1a.add(dccAddressSpinner); 386 dccAddressSpinner.setToolTipText(Bundle.getMessage("DccAddressFieldHint")); 387 initiatePane.add(p1a); 388 JPanel p2 = new JPanel(); 389 p2.setLayout(new FlowLayout()); 390 p2.add(inTransitBox); 391 inTransitBox.addActionListener(new ActionListener() { 392 @Override 393 public void actionPerformed(ActionEvent e) { 394 handleInTransitClick(e); 395 } 396 }); 397 inTransitBox.setToolTipText(Bundle.getMessage("InTransitBoxHint")); 398 initiatePane.add(p2); 399 JPanel p3 = new JPanel(); 400 p3.setLayout(new FlowLayout()); 401 p3.add(new JLabel(Bundle.getMessage("StartingBlockBoxLabel") + " :")); 402 p3.add(startingBlockBox); 403 startingBlockBox.setToolTipText(Bundle.getMessage("StartingBlockBoxHint")); 404 startingBlockBox.addActionListener(new ActionListener() { 405 @Override 406 public void actionPerformed(ActionEvent e) { 407 handleStartingBlockSelectionChanged(e); 408 } 409 }); 410 initiatePane.add(p3); 411 JPanel p4 = new JPanel(); 412 p4.setLayout(new FlowLayout()); 413 p4.add(new JLabel(Bundle.getMessage("DestinationBlockBoxLabel") + ":")); 414 p4.add(destinationBlockBox); 415 destinationBlockBox.setToolTipText(Bundle.getMessage("DestinationBlockBoxHint")); 416 JPanel p4a = new JPanel(); 417 initiatePane.add(p4); 418 p4a.add(trainDetectionLabel); 419 initializeTrainDetectionBox(); 420 p4a.add(trainDetectionComboBox); 421 trainDetectionComboBox.setToolTipText(Bundle.getMessage("TrainDetectionBoxHint")); 422 initiatePane.add(p4a); 423 JPanel p4b = new JPanel(); 424 p4b.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("AllocateMethodLabel"))); 425 p4b.setLayout(new FlowLayout()); 426 allocateMethodButtonGroup.add(allocateAllTheWayRadioButton); 427 allocateMethodButtonGroup.add(allocateBySafeRadioButton); 428 allocateMethodButtonGroup.add(allocateNumberOfBlocks); 429 p4b.add(allocateAllTheWayRadioButton); 430 allocateAllTheWayRadioButton.setToolTipText(Bundle.getMessage("AllocateAllTheWayHint")); 431 p4b.add(allocateBySafeRadioButton); 432 allocateBySafeRadioButton.setToolTipText(Bundle.getMessage("AllocateSafeHint")); 433 p4b.add(allocateNumberOfBlocks); 434 allocateNumberOfBlocks.setToolTipText(Bundle.getMessage("AllocateMethodHint")); 435 allocateAllTheWayRadioButton.addActionListener(new ActionListener() { 436 @Override 437 public void actionPerformed(ActionEvent e) { 438 handleAllocateAllTheWayButtonChanged(e); 439 } 440 }); 441 allocateBySafeRadioButton.addActionListener(new ActionListener() { 442 @Override 443 public void actionPerformed(ActionEvent e) { 444 handleAllocateBySafeButtonChanged(e); 445 } 446 }); 447 allocateNumberOfBlocks.addActionListener(new ActionListener() { 448 @Override 449 public void actionPerformed(ActionEvent e) { 450 handleAllocateNumberOfBlocksButtonChanged(e); 451 } 452 }); 453 p4b.add(allocateCustomSpinner); 454 allocateCustomSpinner.setToolTipText(Bundle.getMessage("AllocateMethodHint")); 455 initiatePane.add(p4b); 456 JPanel p6 = new JPanel(); 457 p6.setLayout(new FlowLayout()); 458 p6.add(resetWhenDoneBox); 459 resetWhenDoneBox.addActionListener(new ActionListener() { 460 @Override 461 public void actionPerformed(ActionEvent e) { 462 handleResetWhenDoneClick(e); 463 } 464 }); 465 resetWhenDoneBox.setToolTipText(Bundle.getMessage("ResetWhenDoneBoxHint")); 466 initiatePane.add(p6); 467 JPanel p6a = new JPanel(); 468 p6a.setLayout(new FlowLayout()); 469 ((FlowLayout) p6a.getLayout()).setVgap(1); 470 p6a.add(delayedReStartLabel); 471 p6a.add(delayedReStartBox); 472 p6a.add(resetRestartSensorBox); 473 resetRestartSensorBox.setToolTipText(Bundle.getMessage("ResetRestartSensorHint")); 474 resetRestartSensorBox.setSelected(true); 475 delayedReStartBox.addActionListener(new ActionListener() { 476 @Override 477 public void actionPerformed(ActionEvent e) { 478 handleResetWhenDoneClick(e); 479 } 480 }); 481 delayedReStartBox.setToolTipText(Bundle.getMessage("DelayedReStartHint")); 482 initiatePane.add(p6a); 483 484 JPanel p6b = new JPanel(); 485 p6b.setLayout(new FlowLayout()); 486 ((FlowLayout) p6b.getLayout()).setVgap(1); 487 p6b.add(delayMinLabel); 488 p6b.add(delayMinSpinner); // already set to 0 489 delayMinSpinner.setToolTipText(Bundle.getMessage("RestartTimedHint")); 490 p6b.add(delayReStartSensorLabel); 491 p6b.add(delayReStartSensor); 492 delayReStartSensor.setAllowNull(true); 493 handleResetWhenDoneClick(null); 494 initiatePane.add(p6b); 495 496 initiatePane.add(new JSeparator()); 497 498 JPanel p10 = new JPanel(); 499 p10.setLayout(new FlowLayout()); 500 p10.add(reverseAtEndBox); 501 reverseAtEndBox.setToolTipText(Bundle.getMessage("ReverseAtEndBoxHint")); 502 initiatePane.add(p10); 503 reverseAtEndBox.addActionListener(new ActionListener() { 504 @Override 505 public void actionPerformed(ActionEvent e) { 506 handleReverseAtEndBoxClick(e); 507 } 508 }); 509 JPanel pDelayReverseRestartDetails = new JPanel(); 510 pDelayReverseRestartDetails.setLayout(new FlowLayout()); 511 ((FlowLayout) pDelayReverseRestartDetails.getLayout()).setVgap(1); 512 pDelayReverseRestartDetails.add(delayReverseReStartLabel); 513 pDelayReverseRestartDetails.add(reverseDelayedRestartType); 514 pDelayReverseRestartDetails.add(delayReverseResetSensorBox); 515 delayReverseResetSensorBox.setToolTipText(Bundle.getMessage("ReverseResetRestartSensorHint")); 516 delayReverseResetSensorBox.setSelected(true); 517 reverseDelayedRestartType.addActionListener(new ActionListener() { 518 @Override 519 public void actionPerformed(ActionEvent e) { 520 handleReverseAtEndBoxClick(e); 521 } 522 }); 523 reverseDelayedRestartType.setToolTipText(Bundle.getMessage("ReverseDelayedReStartHint")); 524 initiatePane.add(pDelayReverseRestartDetails); 525 526 JPanel pDelayReverseRestartDetails2 = new JPanel(); 527 pDelayReverseRestartDetails2.setLayout(new FlowLayout()); 528 ((FlowLayout) pDelayReverseRestartDetails2.getLayout()).setVgap(1); 529 pDelayReverseRestartDetails2.add(delayReverseMinLabel); 530 pDelayReverseRestartDetails2.add(delayReverseMinSpinner); // already set to 0 531 delayReverseMinSpinner.setToolTipText(Bundle.getMessage("ReverseRestartTimedHint")); 532 pDelayReverseRestartDetails2.add(delayReverseReStartSensorLabel); 533 pDelayReverseRestartDetails2.add(delayReverseReStartSensor); 534 delayReverseReStartSensor.setAllowNull(true); 535 handleReverseAtEndBoxClick(null); 536 initiatePane.add(pDelayReverseRestartDetails2); 537 538 initiatePane.add(new JSeparator()); 539 540 JPanel p10a = new JPanel(); 541 p10a.setLayout(new FlowLayout()); 542 p10a.add(terminateWhenDoneBox); 543 terminateWhenDoneBox.addActionListener(new ActionListener() { 544 @Override 545 public void actionPerformed(ActionEvent e) { 546 handleTerminateWhenDoneBoxClick(e); 547 } 548 }); 549 initiatePane.add(p10a); 550 terminateWhenDoneDetails.setLayout(new FlowLayout()); 551 terminateWhenDoneDetails.add(nextTrainLabel); 552 terminateWhenDoneDetails.add(nextTrain); 553 nextTrain.setToolTipText(Bundle.getMessage("TerminateWhenDoneNextTrainHint")); 554 initiatePane.add(terminateWhenDoneDetails); 555 handleTerminateWhenDoneBoxClick(null); 556 557 initiatePane.add(new JSeparator()); 558 559 JPanel p8 = new JPanel(); 560 p8.setLayout(new FlowLayout()); 561 p8.add(new JLabel(Bundle.getMessage("PriorityLabel") + ":")); 562 p8.add(prioritySpinner); // already set to 5 563 prioritySpinner.setToolTipText(Bundle.getMessage("PriorityHint")); 564 p8.add(new JLabel(" ")); 565 p8.add(new JLabel(Bundle.getMessage("TrainTypeBoxLabel"))); 566 initializeTrainTypeBox(); 567 p8.add(trainTypeBox); 568 trainTypeBox.setSelectedIndex(1); 569 trainTypeBox.setToolTipText(Bundle.getMessage("TrainTypeBoxHint")); 570 initiatePane.add(p8); 571 JPanel p9 = new JPanel(); 572 p9.setLayout(new FlowLayout()); 573 p9.add(new JLabel(Bundle.getMessage("DelayedStart"))); 574 p9.add(delayedStartBox); 575 delayedStartBox.setToolTipText(Bundle.getMessage("DelayedStartHint")); 576 delayedStartBox.addActionListener(new ActionListener() { 577 @Override 578 public void actionPerformed(ActionEvent e) { 579 handleDelayStartClick(e); 580 } 581 }); 582 p9.add(departureTimeLabel); 583 departureHrSpinner.setEditor(new JSpinner.NumberEditor(departureHrSpinner, "00")); 584 p9.add(departureHrSpinner); 585 departureHrSpinner.setValue(8); 586 departureHrSpinner.setToolTipText(Bundle.getMessage("DepartureTimeHrHint")); 587 p9.add(departureSepLabel); 588 departureMinSpinner.setEditor(new JSpinner.NumberEditor(departureMinSpinner, "00")); 589 p9.add(departureMinSpinner); 590 departureMinSpinner.setValue(0); 591 departureMinSpinner.setToolTipText(Bundle.getMessage("DepartureTimeMinHint")); 592 p9.add(delaySensor); 593 delaySensor.setAllowNull(true); 594 p9.add(resetStartSensorBox); 595 resetStartSensorBox.setToolTipText(Bundle.getMessage("ResetStartSensorHint")); 596 resetStartSensorBox.setSelected(true); 597 handleDelayStartClick(null); 598 initiatePane.add(p9); 599 600 JPanel p11 = new JPanel(); 601 p11.setLayout(new FlowLayout()); 602 p11.add(loadAtStartupBox); 603 loadAtStartupBox.setToolTipText(Bundle.getMessage("LoadAtStartupBoxHint")); 604 loadAtStartupBox.setSelected(false); 605 initiatePane.add(p11); 606 607 initiatePane.add(new JSeparator()); 608 JPanel p5 = new JPanel(); 609 p5.setLayout(new FlowLayout()); 610 p5.add(autoRunBox); 611 autoRunBox.addActionListener(new ActionListener() { 612 @Override 613 public void actionPerformed(ActionEvent e) { 614 handleAutoRunClick(e); 615 } 616 }); 617 autoRunBox.setToolTipText(Bundle.getMessage("AutoRunBoxHint")); 618 autoRunBox.setSelected(false); 619 initiatePane.add(p5); 620 621 initializeAutoRunItems(); 622 623 JPanel p7 = new JPanel(); 624 p7.setLayout(new FlowLayout()); 625 JButton cancelButton = null; 626 p7.add(cancelButton = new JButton(Bundle.getMessage("ButtonCancel"))); 627 cancelButton.addActionListener(new ActionListener() { 628 @Override 629 public void actionPerformed(ActionEvent e) { 630 cancelInitiateTrain(e); 631 } 632 }); 633 cancelButton.setToolTipText(Bundle.getMessage("CancelButtonHint")); 634 p7.add(addNewTrainButton = new JButton(Bundle.getMessage("ButtonCreate"))); 635 addNewTrainButton.addActionListener(new ActionListener() { 636 @Override 637 public void actionPerformed(ActionEvent e) { 638 addNewTrain(e); 639 } 640 }); 641 addNewTrainButton.setToolTipText(Bundle.getMessage("AddNewTrainButtonHint")); 642 643 JPanel mainPane = new JPanel(); 644 mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); 645 JScrollPane scrPane = new JScrollPane(initiatePane); 646 mainPane.add(p0); 647 mainPane.add(scrPane); 648 mainPane.add(p7); 649 initiateFrame.setContentPane(mainPane); 650 switch (trainInfo.getTrainsFrom()) { 651 case TRAINSFROMROSTER: 652 radioTrainsFromRoster.setSelected(true); 653 break; 654 case TRAINSFROMOPS: 655 radioTrainsFromOps.setSelected(true); 656 break; 657 case TRAINSFROMUSER: 658 radioTrainsFromUser.setSelected(true); 659 break; 660 case TRAINSFROMSETLATER: 661 default: 662 radioTrainsFromSetLater.setSelected(true); 663 } 664 665 } 666 autoRunBox.setSelected(false); 667 loadAtStartupBox.setSelected(false); 668 initializeFreeTransitsCombo(new ArrayList<Transit>()); 669 refreshNextTrainCombo(); 670 setTrainsFromOptions(trainInfo.getTrainsFrom()); 671 initiateFrame.pack(); 672 initiateFrame.setVisible(true); 673 674 trainInfoToDialog(trainInfo); 675 } 676 677 private void refreshNextTrainCombo() { 678 Object saveEntry = null; 679 if (nextTrain.getSelectedIndex() > 0) { 680 saveEntry=nextTrain.getSelectedItem(); 681 } 682 nextTrain.removeAllItems(); 683 nextTrain.addItem(" "); 684 for (String file: _tiFile.getTrainInfoFileNames()) { 685 nextTrain.addItem(file); 686 } 687 if (saveEntry != null) { 688 nextTrain.setSelectedItem(saveEntry); 689 } 690 } 691 private void setTrainsFromOptions(TrainsFrom transFrom) { 692 switch (transFrom) { 693 case TRAINSFROMROSTER: 694 initializeFreeRosterEntriesCombo(); 695 trainBoxLabel.setVisible(true); 696 rosterComboBox.setVisible(true); 697 trainSelectBox.setVisible(false); 698 trainFieldLabel.setVisible(true); 699 trainNameField.setVisible(true); 700 dccAddressFieldLabel.setVisible(false); 701 dccAddressSpinner.setVisible(false); 702 break; 703 case TRAINSFROMOPS: 704 initializeFreeTrainsCombo(); 705 trainBoxLabel.setVisible(true); 706 trainSelectBox.setVisible(true); 707 rosterComboBox.setVisible(false); 708 trainFieldLabel.setVisible(true); 709 trainNameField.setVisible(true); 710 dccAddressFieldLabel.setVisible(true); 711 dccAddressSpinner.setVisible(true); 712 setSpeedProfileOptions(trainInfo,false); 713 break; 714 case TRAINSFROMUSER: 715 trainNameField.setText(""); 716 trainBoxLabel.setVisible(false); 717 trainSelectBox.setVisible(false); 718 rosterComboBox.setVisible(false); 719 trainFieldLabel.setVisible(true); 720 trainNameField.setVisible(true); 721 dccAddressFieldLabel.setVisible(true); 722 dccAddressSpinner.setVisible(true); 723 dccAddressSpinner.setEnabled(true); 724 setSpeedProfileOptions(trainInfo,false); 725 break; 726 case TRAINSFROMSETLATER: 727 default: 728 trainBoxLabel.setVisible(false); 729 rosterComboBox.setVisible(false); 730 trainSelectBox.setVisible(false); 731 trainFieldLabel.setVisible(true); 732 trainNameField.setVisible(true); 733 dccAddressFieldLabel.setVisible(false); 734 dccAddressSpinner.setVisible(false); 735 } 736 } 737 738 private void initializeTrainTypeBox() { 739 trainTypeBox.removeAllItems(); 740 trainTypeBox.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">"); // <none> 741 trainTypeBox.addItem(Bundle.getMessage("LOCAL_PASSENGER")); 742 trainTypeBox.addItem(Bundle.getMessage("LOCAL_FREIGHT")); 743 trainTypeBox.addItem(Bundle.getMessage("THROUGH_PASSENGER")); 744 trainTypeBox.addItem(Bundle.getMessage("THROUGH_FREIGHT")); 745 trainTypeBox.addItem(Bundle.getMessage("EXPRESS_PASSENGER")); 746 trainTypeBox.addItem(Bundle.getMessage("EXPRESS_FREIGHT")); 747 trainTypeBox.addItem(Bundle.getMessage("MOW")); 748 // NOTE: The above must correspond in order and name to definitions in ActiveTrain.java. 749 } 750 751 private void initializeTrainDetectionBox() { 752 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionWholeTrain"),TrainDetection.TRAINDETECTION_WHOLETRAIN)); 753 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadAndTail"),TrainDetection.TRAINDETECTION_HEADANDTAIL)); 754 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadOnly"),TrainDetection.TRAINDETECTION_HEADONLY)); 755 } 756 757 private void initializeScaleLengthBox() { 758 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleFeet"), TrainLengthUnits.TRAINLENGTH_SCALEFEET)); 759 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleMeters"), TrainLengthUnits.TRAINLENGTH_SCALEMETERS)); 760 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualInchs"), TrainLengthUnits.TRAINLENGTH_ACTUALINCHS)); 761 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualcm"), TrainLengthUnits.TRAINLENGTH_ACTUALCM)); 762 } 763 764 private void handleTransitSelectionChanged(ActionEvent e) { 765 int index = transitSelectBox.getSelectedIndex(); 766 if (index < 0) { 767 return; 768 } 769 Transit t = transitSelectBox.getSelectedItem(); 770 if ((t != null) && (t != selectedTransit)) { 771 selectedTransit = t; 772 initializeStartingBlockCombo(); 773 initializeDestinationBlockCombo(); 774 initiateFrame.pack(); 775 } 776 } 777 778 private void handleInTransitClick(ActionEvent e) { 779 if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) { 780 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle 781 .getMessage("NoEntryBlocks"), Bundle.getMessage("MessageTitle"), 782 JmriJOptionPane.INFORMATION_MESSAGE); 783 inTransitBox.setSelected(true); 784 } 785 initializeStartingBlockCombo(); 786 initializeDestinationBlockCombo(); 787 initiateFrame.pack(); 788 } 789 790 // private void handleTrainSelectionChanged(ActionEvent e) { 791 private void handleTrainSelectionChanged() { 792 if (trainInfo.getTrainsFrom() != TrainsFrom.TRAINSFROMOPS) { 793 return; 794 } 795 int ix = trainSelectBox.getSelectedIndex(); 796 if (ix < 1) { // no train selected 797 dccAddressSpinner.setEnabled(false); 798 return; 799 } 800 dccAddressSpinner.setEnabled(true); 801 int dccAddress; 802 try { 803 dccAddress = Integer.parseInt((((Train) trainSelectBox.getSelectedItem()).getLeadEngineDccAddress())); 804 } catch (NumberFormatException Ex) { 805 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error43"), 806 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 807 return; 808 } 809 dccAddressSpinner.setValue (dccAddress); 810 } 811 812 private void handleRosterSelectionChanged(ActionEvent e) { 813 if (trainInfo.getTrainsFrom() != TrainsFrom.TRAINSFROMROSTER) { 814 return; 815 } 816 int ix = rosterComboBox.getSelectedIndex(); 817 if (ix > 0) { // first item is "Select Loco" string 818 RosterEntry r = (RosterEntry) rosterComboBox.getItemAt(ix); 819 // check to see if speed profile exists and is not empty 820 if (r.getSpeedProfile() == null || r.getSpeedProfile().getProfileSize() < 1) { 821 // disable profile boxes etc. 822 setSpeedProfileOptions(trainInfo,false); 823 } else { 824 // enable profile boxes 825 setSpeedProfileOptions(trainInfo,true); 826 } 827 trainInfo.setMaxSpeed(r.getMaxSpeedPCT()/100.0f); 828 maxSpeedSpinner.setValue(trainInfo.getMaxSpeed()); 829 trainNameField.setText(r.titleString()); 830 if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) { 831 trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType")); 832 } 833 } else { 834 setSpeedProfileOptions(trainInfo,false); 835 } 836 } 837 838 private void handleDelayStartClick(ActionEvent e) { 839 departureHrSpinner.setVisible(false); 840 departureMinSpinner.setVisible(false); 841 departureTimeLabel.setVisible(false); 842 departureSepLabel.setVisible(false); 843 delaySensor.setVisible(false); 844 resetStartSensorBox.setVisible(false); 845 if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 846 departureHrSpinner.setVisible(true); 847 departureMinSpinner.setVisible(true); 848 departureTimeLabel.setVisible(true); 849 departureSepLabel.setVisible(true); 850 } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 851 delaySensor.setVisible(true); 852 resetStartSensorBox.setVisible(true); 853 } 854 initiateFrame.pack(); // to fit extra hh:mm in window 855 } 856 857 private void handleResetWhenDoneClick(ActionEvent e) { 858 delayMinSpinner.setVisible(false); 859 delayMinLabel.setVisible(false); 860 delayedReStartLabel.setVisible(false); 861 delayedReStartBox.setVisible(false); 862 delayReStartSensorLabel.setVisible(false); 863 delayReStartSensor.setVisible(false); 864 resetRestartSensorBox.setVisible(false); 865 if (resetWhenDoneBox.isSelected()) { 866 delayedReStartLabel.setVisible(true); 867 delayedReStartBox.setVisible(true); 868 terminateWhenDoneBox.setSelected(false); 869 if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 870 delayMinSpinner.setVisible(true); 871 delayMinLabel.setVisible(true); 872 } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 873 delayReStartSensor.setVisible(true); 874 delayReStartSensorLabel.setVisible(true); 875 resetRestartSensorBox.setVisible(true); 876 } 877 } else { 878 terminateWhenDoneBox.setEnabled(true); 879 } 880 initiateFrame.pack(); 881 } 882 883 private void handleTerminateWhenDoneBoxClick(ActionEvent e) { 884 if (terminateWhenDoneBox.isSelected()) { 885 refreshNextTrainCombo(); 886 resetWhenDoneBox.setSelected(false); 887 terminateWhenDoneDetails.setVisible(true); 888 } else { 889 terminateWhenDoneDetails.setVisible(false); 890 // leave it 891 //nextTrain.setSelectedItem(""); 892 } 893 } 894 private void handleReverseAtEndBoxClick(ActionEvent e) { 895 delayReverseMinSpinner.setVisible(false); 896 delayReverseMinLabel.setVisible(false); 897 delayReverseReStartLabel.setVisible(false); 898 reverseDelayedRestartType.setVisible(false); 899 delayReverseReStartSensorLabel.setVisible(false); 900 delayReverseReStartSensor.setVisible(false); 901 delayReverseResetSensorBox.setVisible(false); 902 if (reverseAtEndBox.isSelected()) { 903 delayReverseReStartLabel.setVisible(true); 904 reverseDelayedRestartType.setVisible(true); 905 if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 906 delayReverseMinSpinner.setVisible(true); 907 delayReverseMinLabel.setVisible(true); 908 } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 909 delayReverseReStartSensor.setVisible(true); 910 delayReStartSensorLabel.setVisible(true); 911 delayReverseResetSensorBox.setVisible(true); 912 } 913 } 914 initiateFrame.pack(); 915 916 if (resetWhenDoneBox.isSelected()) { 917 terminateWhenDoneBox.setSelected(false); 918 terminateWhenDoneBox.setEnabled(false); 919 } else { 920 terminateWhenDoneBox.setEnabled(true); 921 } 922 } 923 924 private void handleAutoRunClick(ActionEvent e) { 925 if (autoRunBox.isSelected()) { 926 showAutoRunItems(); 927 } else { 928 hideAutoRunItems(); 929 } 930 initiateFrame.pack(); 931 } 932 933 private void handleStartingBlockSelectionChanged(ActionEvent e) { 934 initializeDestinationBlockCombo(); 935 initiateFrame.pack(); 936 } 937 938 private void handleAllocateAllTheWayButtonChanged(ActionEvent e) { 939 allocateCustomSpinner.setVisible(false); 940 } 941 942 private void handleAllocateBySafeButtonChanged(ActionEvent e) { 943 allocateCustomSpinner.setVisible(false); 944 } 945 946 private void handleAllocateNumberOfBlocksButtonChanged(ActionEvent e) { 947 allocateCustomSpinner.setVisible(true); 948 } 949 950 private void cancelInitiateTrain(ActionEvent e) { 951 _dispatcher.newTrainDone(null); 952 } 953 954 /* 955 * Handles press of "Add New Train" button. 956 * Move data to TrainInfo validating basic information 957 * Call dispatcher to start the train from traininfo which 958 * completes validation. 959 */ 960 private void addNewTrain(ActionEvent e) { 961 try { 962 validateDialog(); 963 dialogToTrainInfo(trainInfo); 964 _dispatcher.loadTrainFromTrainInfoThrowsException(trainInfo,"NONE",""); 965 } catch (IllegalArgumentException ex) { 966 JmriJOptionPane.showMessageDialog(initiateFrame, ex.getMessage(), 967 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 968 } 969 } 970 971 private void initializeFreeTransitsCombo(List<Transit> transitList) { 972 Set<Transit> excludeTransits = new HashSet<>(); 973 for (Transit t : _TransitManager.getNamedBeanSet()) { 974 if (t.getState() != Transit.IDLE) { 975 excludeTransits.add(t); 976 } 977 } 978 transitSelectBox.setExcludedItems(excludeTransits); 979 JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox); 980 981 if (transitSelectBox.getItemCount() > 0) { 982 transitSelectBox.setSelectedIndex(0); 983 selectedTransit = transitSelectBox.getItemAt(0); 984 } else { 985 selectedTransit = null; 986 } 987 } 988 989 private void initializeFreeRosterEntriesCombo() { 990 rosterComboBox.update(); 991 // remove used entries 992 for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) { // remove from back first item is the "select loco" message 993 if ( !_dispatcher.isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) { 994 rosterComboBox.removeItemAt(ix); 995 } 996 } 997 } 998 999 private void initializeFreeTrainsCombo() { 1000 ActionListener[] als = trainSelectBox.getActionListeners(); 1001 for ( ActionListener al: als) { 1002 trainSelectBox.removeActionListener(al); 1003 } 1004 trainSelectBox.removeAllItems(); 1005 trainSelectBox.addItem("Select Train"); 1006 // initialize free trains from operations 1007 List<Train> trains = jmri.InstanceManager.getDefault(TrainManager.class).getTrainsByNameList(); 1008 if (trains.size() > 0) { 1009 for (int i = 0; i < trains.size(); i++) { 1010 Train t = trains.get(i); 1011 if (t != null) { 1012 String tName = t.getName(); 1013 if (_dispatcher.isTrainFree(tName)) { 1014 trainSelectBox.addItem(t); 1015 } 1016 } 1017 } 1018 } 1019 for ( ActionListener al: als) { 1020 trainSelectBox.addActionListener(al); 1021 } 1022 } 1023 1024 /** 1025 * Sets the labels and inputs for speed profile running 1026 * @param b True if the roster entry has valid speed profile else false 1027 */ 1028 private void setSpeedProfileOptions(TrainInfo info,boolean b) { 1029 useSpeedProfileLabel.setEnabled(b); 1030 useSpeedProfileCheckBox.setEnabled(b); 1031 stopBySpeedProfileLabel.setEnabled(b); 1032 stopBySpeedProfileCheckBox.setEnabled(b); 1033 stopBySpeedProfileAdjustLabel.setEnabled(b); 1034 stopBySpeedProfileAdjustSpinner.setEnabled(b); 1035 if (!b) { 1036 useSpeedProfileCheckBox.setSelected(false); 1037 stopBySpeedProfileCheckBox.setSelected(false); 1038 info.setUseSpeedProfile(false); 1039 info.setStopBySpeedProfile(false); 1040 } 1041 } 1042 1043 1044 1045 private void initializeStartingBlockCombo() { 1046 startingBlockBox.removeAllItems(); 1047 startingBlockBoxList.clear(); 1048 if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) { 1049 inTransitBox.setSelected(true); 1050 } 1051 if (inTransitBox.isSelected()) { 1052 startingBlockBoxList = selectedTransit.getInternalBlocksList(); 1053 } else { 1054 startingBlockBoxList = selectedTransit.getEntryBlocksList(); 1055 } 1056 startingBlockSeqList = selectedTransit.getBlockSeqList(); 1057 boolean found = false; 1058 for (int i = 0; i < startingBlockBoxList.size(); i++) { 1059 Block b = startingBlockBoxList.get(i); 1060 int seq = startingBlockSeqList.get(i).intValue(); 1061 startingBlockBox.addItem(getBlockName(b) + "-" + seq); 1062 if (!found && b.getState() == Block.OCCUPIED) { 1063 startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq); 1064 found = true; 1065 } 1066 } 1067 JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox); 1068 } 1069 1070 private void initializeDestinationBlockCombo() { 1071 destinationBlockBox.removeAllItems(); 1072 destinationBlockBoxList.clear(); 1073 int index = startingBlockBox.getSelectedIndex(); 1074 if (index < 0) { 1075 return; 1076 } 1077 Block startBlock = startingBlockBoxList.get(index); 1078 destinationBlockBoxList = selectedTransit.getDestinationBlocksList( 1079 startBlock, inTransitBox.isSelected()); 1080 destinationBlockSeqList = selectedTransit.getDestBlocksSeqList(); 1081 for (int i = 0; i < destinationBlockBoxList.size(); i++) { 1082 Block b = destinationBlockBoxList.get(i); 1083 String bName = getBlockName(b); 1084 if (selectedTransit.getBlockCount(b) > 1) { 1085 int seq = destinationBlockSeqList.get(i).intValue(); 1086 bName = bName + "-" + seq; 1087 } 1088 destinationBlockBox.addItem(bName); 1089 } 1090 JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox); 1091 } 1092 1093 private String getBlockName(Block b) { 1094 if (b != null) { 1095 return b.getDisplayName(); 1096 } 1097 return " "; 1098 } 1099 1100 protected void showActivateFrame() { 1101 if (initiateFrame != null) { 1102 initializeFreeTransitsCombo(new ArrayList<Transit>()); 1103 initiateFrame.setVisible(true); 1104 } else { 1105 _dispatcher.newTrainDone(null); 1106 } 1107 } 1108 1109 public void showActivateFrame(RosterEntry re) { 1110 showActivateFrame(); 1111 } 1112 1113 private void loadTrainInfo(ActionEvent e) { 1114 List<TrainInfoFileSummary> names = _tiFile.getTrainInfoFileSummaries(); 1115 if (names.size() > 0) { 1116 JTable table = new JTable(){ 1117 @Override 1118 public Dimension getPreferredScrollableViewportSize() { 1119 return new Dimension(super.getPreferredSize().width, 1120 super.getPreferredScrollableViewportSize().height); 1121 } 1122 }; 1123 DefaultTableModel tm = new DefaultTableModel( 1124 new Object[]{ 1125 Bundle.getMessage("FileNameColumnTitle"), 1126 Bundle.getMessage("TrainColumnTitle"), 1127 Bundle.getMessage("TransitColumnTitle"), 1128 Bundle.getMessage("StartBlockColumnTitle"), 1129 Bundle.getMessage("EndBlockColumnTitle"), 1130 Bundle.getMessage("DccColumnTitleColumnTitle") 1131 }, 0) { 1132 @Override 1133 public boolean isCellEditable(int row, int column) { 1134 //all cells false 1135 return false; 1136 } 1137 }; 1138 1139 table.setModel(tm); 1140 for (TrainInfoFileSummary fs: names) { 1141 tm.addRow(new Object[] {fs.getFileName(),fs.getTrainName(), 1142 fs.getTransitName(),fs.getStartBlockName() 1143 ,fs.getEndBlockName(),fs.getDccAddress()}); 1144 } 1145 JPanel jp = new JPanel(new BorderLayout()); 1146 TableColumnModel columnModel = table.getColumnModel(); 1147 table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF ); 1148 for (int column = 0; column < table.getColumnCount(); column++) { 1149 int width = 30; // Min width 1150 for (int row = 0; row < table.getRowCount(); row++) { 1151 TableCellRenderer renderer = table.getCellRenderer(row, column); 1152 Component comp = table.prepareRenderer(renderer, row, column); 1153 width = Math.max(comp.getPreferredSize().width +1 , width); 1154 } 1155 if(width > 300) 1156 width=300; 1157 columnModel.getColumn(column).setPreferredWidth(width); 1158 } 1159 //jp.setPreferredSize(table.getPreferredSize()); 1160 jp.add(table); 1161 JScrollPane sp = new JScrollPane(table, 1162 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 1163 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 1164 int optionSelected = JmriJOptionPane.showOptionDialog(initiateFrame, 1165 sp, Bundle.getMessage("LoadTrainTitle"), JmriJOptionPane.OK_CANCEL_OPTION, JmriJOptionPane.PLAIN_MESSAGE, 1166 null,null,null); 1167 if (optionSelected != JmriJOptionPane.OK_OPTION) { 1168 //Canceled 1169 return; 1170 } 1171 if (table.getSelectedRow() < 0) { 1172 return; 1173 } 1174 String selName = (String)table.getModel().getValueAt(table.getSelectedRow(),0); 1175 if ((selName == null) || (selName.isEmpty())) { 1176 return; 1177 } 1178 //read xml data from selected filename and move it into the new train dialog box 1179 _trainInfoName = selName; 1180 try { 1181 trainInfo = _tiFile.readTrainInfo( selName); 1182 if (trainInfo != null) { 1183 // process the information just read 1184 trainInfoToDialog(trainInfo); 1185 } 1186 } catch (java.io.IOException ioe) { 1187 log.error("IO Exception when reading train info file", ioe); 1188 } catch (org.jdom2.JDOMException jde) { 1189 log.error("JDOM Exception when reading train info file", jde); 1190 } 1191 } 1192 handleDelayStartClick(null); 1193 handleReverseAtEndBoxClick(null); 1194 } 1195 1196 private void saveTrainInfo(ActionEvent e) { 1197 saveTrainInfo(false); 1198 refreshNextTrainCombo(); 1199 } 1200 1201 private void saveTrainInfoAsTemplate(ActionEvent e) { 1202 saveTrainInfo(true); 1203 } 1204 1205 private void saveTrainInfo(boolean asTemplate) { 1206 try { 1207 dialogToTrainInfo(trainInfo); 1208 } catch (IllegalArgumentException ide) { 1209 JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(), 1210 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1211 return; 1212 } 1213 // get file name 1214 String fileName; 1215 if (asTemplate) { 1216 fileName = normalizeXmlFileName(nameOfTemplateFile); 1217 } else { 1218 String eName = ""; 1219 eName = JmriJOptionPane.showInputDialog(initiateFrame, 1220 Bundle.getMessage("EnterFileName") + " :", _trainInfoName); 1221 if (eName == null) { //Cancel pressed 1222 return; 1223 } 1224 if (eName.length() < 1) { 1225 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"), 1226 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1227 return; 1228 } 1229 fileName = normalizeXmlFileName(eName); 1230 _trainInfoName = fileName; 1231 } 1232 // check if train info file name is in use 1233 String[] names = _tiFile.getTrainInfoFileNames(); 1234 if (names.length > 0) { 1235 boolean found = false; 1236 for (int i = 0; i < names.length; i++) { 1237 if (fileName.equals(names[i])) { 1238 found = true; 1239 } 1240 } 1241 if (found) { 1242 // file by that name is already present 1243 int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame, 1244 Bundle.getMessage("Question3", fileName), 1245 Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION, 1246 JmriJOptionPane.QUESTION_MESSAGE, null, 1247 new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")}, 1248 Bundle.getMessage("ButtonNo")); 1249 if (selectedValue != 0 ) { // array position 0 , replace not selected 1250 return; // return without writing if "No" response 1251 } 1252 } 1253 } 1254 // write the Train Info file 1255 try { 1256 _tiFile.writeTrainInfo(trainInfo, fileName); 1257 } //catch (org.jdom2.JDOMException jde) { 1258 // log.error("JDOM exception writing Train Info: "+jde); 1259 //} 1260 catch (java.io.IOException ioe) { 1261 log.error("IO exception writing Train Info", ioe); 1262 } 1263 } 1264 1265 private void deleteTrainInfo(ActionEvent e) { 1266 String[] names = _tiFile.getTrainInfoFileNames(); 1267 if (names.length > 0) { 1268 Object selName = JmriJOptionPane.showInputDialog(initiateFrame, 1269 Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"), 1270 JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]); 1271 if ((selName == null) || (((String) selName).equals(""))) { 1272 return; 1273 } 1274 _tiFile.deleteTrainInfoFile((String) selName); 1275 } 1276 } 1277 1278 private void trainInfoToDialog(TrainInfo info) { 1279 if (!info.getTransitName().isEmpty()) { 1280 try { 1281 transitSelectBox.setSelectedItemByName(info.getTransitName()); 1282 } catch (Exception ex) { 1283 log.warn("Transit {} from file not in Transit menu", info.getTransitName()); 1284 JmriJOptionPane.showMessageDialog(initiateFrame, 1285 Bundle.getMessage("TransitWarn", info.getTransitName()), 1286 null, JmriJOptionPane.WARNING_MESSAGE); 1287 } 1288 } 1289 switch (info.getTrainsFrom()) { 1290 case TRAINSFROMROSTER: 1291 radioTrainsFromRoster.setSelected(true); 1292 if (!info.getRosterId().isEmpty()) { 1293 if (!setRosterComboBox(rosterComboBox, info.getRosterId())) { 1294 log.warn("Roster {} from file not in Roster Combo", info.getRosterId()); 1295 JmriJOptionPane.showMessageDialog(initiateFrame, 1296 Bundle.getMessage("TrainWarn", info.getRosterId()), 1297 null, JmriJOptionPane.WARNING_MESSAGE); 1298 } 1299 } 1300 break; 1301 case TRAINSFROMOPS: 1302 radioTrainsFromOps.setSelected(true); 1303 if (!info.getTrainName().isEmpty()) { 1304 if (!setTrainComboBox(trainSelectBox, info.getTrainName())) { 1305 log.warn("Train {} from file not in Train Combo", info.getTrainName()); 1306 JmriJOptionPane.showMessageDialog(initiateFrame, 1307 Bundle.getMessage("TrainWarn", info.getTrainName()), 1308 null, JmriJOptionPane.WARNING_MESSAGE); 1309 } 1310 } 1311 break; 1312 case TRAINSFROMUSER: 1313 radioTrainsFromUser.setSelected(true); 1314 dccAddressSpinner.setValue(Integer.parseInt(info.getDccAddress())); 1315 break; 1316 case TRAINSFROMSETLATER: 1317 default: 1318 radioTrainsFromSetLater.setSelected(true); 1319 } 1320 trainNameField.setText(info.getTrainUserName()); 1321 trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection()); 1322 inTransitBox.setSelected(info.getTrainInTransit()); 1323 initializeStartingBlockCombo(); 1324 initializeDestinationBlockCombo(); 1325 setComboBox(startingBlockBox, info.getStartBlockName()); 1326 setComboBox(destinationBlockBox, info.getDestinationBlockName()); 1327 setAllocateMethodButtons(info.getAllocationMethod()); 1328 prioritySpinner.setValue(info.getPriority()); 1329 resetWhenDoneBox.setSelected(info.getResetWhenDone()); 1330 reverseAtEndBox.setSelected(info.getReverseAtEnd()); 1331 setDelayModeBox(info.getDelayedStart(), delayedStartBox); 1332 //delayedStartBox.setSelected(info.getDelayedStart()); 1333 departureHrSpinner.setValue(info.getDepartureTimeHr()); 1334 departureMinSpinner.setValue(info.getDepartureTimeMin()); 1335 delaySensor.setSelectedItem(info.getDelaySensor()); 1336 resetStartSensorBox.setSelected(info.getResetStartSensor()); 1337 setDelayModeBox(info.getDelayedRestart(), delayedReStartBox); 1338 delayMinSpinner.setValue(info.getRestartDelayMin()); 1339 delayReStartSensor.setSelectedItem(info.getRestartSensor()); 1340 resetRestartSensorBox.setSelected(info.getResetRestartSensor()); 1341 1342 resetStartSensorBox.setSelected(info.getResetStartSensor()); 1343 setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType); 1344 delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin()); 1345 delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor()); 1346 delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor()); 1347 1348 terminateWhenDoneBox.setSelected(info.getTerminateWhenDone()); 1349 nextTrain.setSelectedIndex(-1); 1350 1351 try { 1352 nextTrain.setSelectedItem(info.getNextTrain()); 1353 } catch (Exception ex){ 1354 nextTrain.setSelectedIndex(-1); 1355 } 1356 handleTerminateWhenDoneBoxClick(null); 1357 setComboBox(trainTypeBox, info.getTrainType()); 1358 autoRunBox.setSelected(info.getAutoRun()); 1359 loadAtStartupBox.setSelected(info.getLoadAtStartup()); 1360 setAllocateMethodButtons(info.getAllocationMethod()); 1361 autoTrainInfoToDialog(info); 1362 } 1363 1364 private boolean validateDialog() throws IllegalArgumentException { 1365 int index = transitSelectBox.getSelectedIndex(); 1366 if (index < 0) { 1367 throw new IllegalArgumentException(Bundle.getMessage("Error44")); 1368 } 1369 switch (trainsFromButtonGroup.getSelection().getActionCommand()) { 1370 case "TRAINSFROMROSTER": 1371 if (rosterComboBox.getSelectedIndex() < 1 ) { 1372 throw new IllegalArgumentException(Bundle.getMessage("Error41")); 1373 } 1374 break; 1375 case "TRAINSFROMOPS": 1376 if (trainSelectBox.getSelectedIndex() < 1) { 1377 throw new IllegalArgumentException(Bundle.getMessage("Error42")); 1378 } 1379 break; 1380 case "TRAINSFROMUSER": 1381 if (trainNameField.getText().isEmpty()) { 1382 throw new IllegalArgumentException(Bundle.getMessage("Error22")); 1383 } 1384 break; 1385 case "TRAINSFROMSETLATER": 1386 default: 1387 } 1388 index = startingBlockBox.getSelectedIndex(); 1389 if (index < 0) { 1390 throw new IllegalArgumentException(Bundle.getMessage("Error13")); 1391 } 1392 index = destinationBlockBox.getSelectedIndex(); 1393 if (index < 0) { 1394 throw new IllegalArgumentException(Bundle.getMessage("Error8")); 1395 } 1396 if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected() 1397 && (!selectedTransit.canBeResetWhenDone())) { 1398 resetWhenDoneBox.setSelected(false); 1399 throw new IllegalArgumentException(Bundle.getMessage("NoResetMessage")); 1400 } 1401 int max = Math.round((float) maxSpeedSpinner.getValue()*100.0f); 1402 int min = Math.round((float) minReliableOperatingSpeedSpinner.getValue()*100.0f); 1403 if ((max-min) < 10) { 1404 throw new IllegalArgumentException(Bundle.getMessage("Error49", 1405 maxSpeedSpinner.getValue(), minReliableOperatingSpeedSpinner.getValue())); 1406 } 1407 return true; 1408 } 1409 1410 private boolean dialogToTrainInfo(TrainInfo info) { 1411 int index = transitSelectBox.getSelectedIndex(); 1412 if (index >= 0 ) { 1413 info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName()); 1414 info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName()); 1415 } 1416 switch (trainsFromButtonGroup.getSelection().getActionCommand()) { 1417 case "TRAINSFROMROSTER": 1418 info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId()); 1419 info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress()); 1420 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER); 1421 setTrainsFromOptions(trainInfo.getTrainsFrom()); 1422 break; 1423 case "TRAINSFROMOPS": 1424 info.setTrainName(((Train) trainSelectBox.getSelectedItem()).getId()); 1425 info.setDccAddress(String.valueOf(dccAddressSpinner.getValue())); 1426 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER); 1427 setTrainsFromOptions(trainInfo.getTrainsFrom()); 1428 break; 1429 case "TRAINSFROMUSER": 1430 info.setDccAddress(String.valueOf(dccAddressSpinner.getValue())); 1431 break; 1432 case "TRAINSFROMSETLATER": 1433 default: 1434 info.setTrainName(""); 1435 info.setDccAddress(""); 1436 } 1437 info.setTrainUserName(trainNameField.getText()); 1438 info.setTrainInTransit(inTransitBox.isSelected()); 1439 info.setStartBlockName((String) startingBlockBox.getSelectedItem()); 1440 index = startingBlockBox.getSelectedIndex(); 1441 info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName()); 1442 info.setStartBlockSeq(startingBlockSeqList.get(index).intValue()); 1443 info.setDestinationBlockName((String) destinationBlockBox.getSelectedItem()); 1444 index = destinationBlockBox.getSelectedIndex(); 1445 info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName()); 1446 info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue()); 1447 info.setPriority((Integer) prioritySpinner.getValue()); 1448 info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value); 1449 info.setResetWhenDone(resetWhenDoneBox.isSelected()); 1450 info.setReverseAtEnd(reverseAtEndBox.isSelected()); 1451 info.setDelayedStart(delayModeFromBox(delayedStartBox)); 1452 info.setDelaySensorName(delaySensor.getSelectedItemDisplayName()); 1453 info.setResetStartSensor(resetStartSensorBox.isSelected()); 1454 info.setDepartureTimeHr((Integer) departureHrSpinner.getValue()); 1455 info.setDepartureTimeMin((Integer) departureMinSpinner.getValue()); 1456 info.setTrainType((String) trainTypeBox.getSelectedItem()); 1457 info.setAutoRun(autoRunBox.isSelected()); 1458 info.setLoadAtStartup(loadAtStartupBox.isSelected()); 1459 info.setAllocateAllTheWay(false); // force to false next field is now used. 1460 if (allocateAllTheWayRadioButton.isSelected()) { 1461 info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN); 1462 } else if (allocateBySafeRadioButton.isSelected()) { 1463 info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS); 1464 } else { 1465 info.setAllocationMethod((Integer) allocateCustomSpinner.getValue()); 1466 } 1467 info.setDelayedRestart(delayModeFromBox(delayedReStartBox)); 1468 info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName()); 1469 info.setResetRestartSensor(resetRestartSensorBox.isSelected()); 1470 info.setRestartDelayMin((Integer) delayMinSpinner.getValue()); 1471 1472 info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType)); 1473 info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName()); 1474 info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected()); 1475 info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue()); 1476 1477 info.setTerminateWhenDone(terminateWhenDoneBox.isSelected()); 1478 if (nextTrain.getSelectedIndex() > 0 ) { 1479 info.setNextTrain((String)nextTrain.getSelectedItem()); 1480 } else { 1481 info.setNextTrain("None"); 1482 } 1483 autoRunItemsToTrainInfo(info); 1484 return true; 1485 } 1486 1487 private boolean setRosterComboBox(RosterEntryComboBox box, String txt) { 1488 boolean found = false; 1489 for (int i = 1; i < box.getItemCount(); i++) { 1490 if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) { 1491 box.setSelectedIndex(i); 1492 found = true; 1493 break; 1494 } 1495 } 1496 if (!found && box.getItemCount() > 0) { 1497 box.setSelectedIndex(0); 1498 } 1499 return found; 1500 } 1501 1502 // Normalizes a suggested xml file name. Returns null string if a valid name cannot be assembled 1503 private String normalizeXmlFileName(String name) { 1504 if (name.length() < 1) { 1505 return ""; 1506 } 1507 String newName = name; 1508 // strip off .xml or .XML if present 1509 if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) { 1510 newName = name.substring(0, name.length() - 4); 1511 if (newName.length() < 1) { 1512 return ""; 1513 } 1514 } 1515 // replace all non-alphanumeric characters with underscore 1516 newName = newName.replaceAll("[\\W]", "_"); 1517 return (newName + ".xml"); 1518 } 1519 1520 private boolean setTrainComboBox(JComboBox<Object> box, String txt) { 1521 boolean found = false; 1522 for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item 1523 if (txt.equals(box.getItemAt(i).toString())) { 1524 box.setSelectedIndex(i); 1525 found = true; 1526 break; 1527 } 1528 } 1529 if (!found && box.getItemCount() > 0) { 1530 box.setSelectedIndex(0); 1531 } 1532 return found; 1533 } 1534 1535 private boolean setComboBox(JComboBox<String> box, String txt) { 1536 boolean found = false; 1537 for (int i = 0; i < box.getItemCount(); i++) { 1538 if (txt.equals(box.getItemAt(i))) { 1539 box.setSelectedIndex(i); 1540 found = true; 1541 break; 1542 } 1543 } 1544 if (!found && box.getItemCount() > 0) { 1545 box.setSelectedIndex(0); 1546 } 1547 return found; 1548 } 1549 1550 int delayModeFromBox(JComboBox<String> box) { 1551 String mode = (String) box.getSelectedItem(); 1552 int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString); 1553 1554 if (result < 0) { 1555 log.warn("unexpected mode string in turnoutMode: {}", mode); 1556 throw new IllegalArgumentException(); 1557 } 1558 return result; 1559 } 1560 1561 void setDelayModeBox(int mode, JComboBox<String> box) { 1562 String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString); 1563 box.setSelectedItem(result); 1564 } 1565 1566 /** 1567 * The following are for items that are only for automatic running of 1568 * ActiveTrains They are isolated here to simplify changing them in the 1569 * future. 1570 * <ul> 1571 * <li>initializeAutoRunItems - initializes the display of auto run items in 1572 * this window 1573 * <li>initializeAutoRunValues - initializes the values of auto run items 1574 * from values in a saved train info file hideAutoRunItems - hides all auto 1575 * run items in this window showAutoRunItems - shows all auto run items in 1576 * this window 1577 * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts 1578 * values in items, and initializes auto run dialog items 1579 * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train 1580 * info for saving to a file 1581 * <li>readAutoRunItems - reads and checks values of all auto run items. 1582 * returns true if OK, sends appropriate messages and returns false if not 1583 * OK 1584 * <li>setAutoRunItems - sets the user entered auto run items in the new 1585 * AutoActiveTrain 1586 * </ul> 1587 */ 1588 // auto run items in ActivateTrainFrame 1589 private final JPanel pa1 = new JPanel(); 1590 private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel")); 1591 private final JSpinner speedFactorSpinner = new JSpinner(); 1592 private final JLabel minReliableOperatingSpeedLabel = new JLabel(Bundle.getMessage("MinReliableOperatingSpeedLabel")); 1593 private final JSpinner minReliableOperatingSpeedSpinner = new JSpinner(); 1594 private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel")); 1595 private final JSpinner maxSpeedSpinner = new JSpinner(); 1596 private final JPanel pa2 = new JPanel(); 1597 private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel")); 1598 private final JComboBox<String> rampRateBox = new JComboBox<>(); 1599 private final JPanel pa2a = new JPanel(); 1600 private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel")); 1601 private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( ); 1602 private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel")); 1603 private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( ); 1604 private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel")); 1605 private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner(); 1606 private final JPanel pa3 = new JPanel(); 1607 private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder")); 1608 private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse")); 1609 private final JPanel pa4 = new JPanel(); 1610 1611 protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> { 1612 public void setSelectedItemByValue(TrainDetection var) { 1613 for ( int ix = 0; ix < getItemCount() ; ix ++ ) { 1614 if (getItemAt(ix).value == var) { 1615 this.setSelectedIndex(ix); 1616 break; 1617 } 1618 } 1619 } 1620 } 1621 private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection")); 1622 public final TrainDetectionJCombo trainDetectionComboBox 1623 = new TrainDetectionJCombo(); 1624 1625 protected static class TrainLengthUnitsJCombo extends JComboBox<TrainLengthUnitsItem> { 1626 public void setSelectedItemByValue(TrainLengthUnits var) { 1627 for ( int ix = 0; ix < getItemCount() ; ix ++ ) { 1628 if (getItemAt(ix).value == var) { 1629 this.setSelectedIndex(ix); 1630 break; 1631 } 1632 } 1633 } 1634 } 1635 public final TrainLengthUnitsJCombo trainLengthUnitsComboBox = new TrainLengthUnitsJCombo(); 1636 private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel")); 1637 private JLabel trainLengthAltLengthLabel; 1638 private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later 1639 1640 private void initializeAutoRunItems() { 1641 initializeRampCombo(); 1642 initializeScaleLengthBox(); 1643 pa1.setLayout(new FlowLayout()); 1644 pa1.add(speedFactorLabel); 1645 speedFactorSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f))); 1646 speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %")); 1647 pa1.add(speedFactorSpinner); 1648 speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint")); 1649 pa1.add(new JLabel(" ")); 1650 pa1.add(maxSpeedLabel); 1651 maxSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(1.0f), Float.valueOf(0.01f))); 1652 maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %")); 1653 pa1.add(maxSpeedSpinner); 1654 maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint")); 1655 pa1.add(minReliableOperatingSpeedLabel); 1656 minReliableOperatingSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(0.0f), Float.valueOf(0.0f), Float.valueOf(1.0f), Float.valueOf(0.01f))); 1657 minReliableOperatingSpeedSpinner.setEditor(new JSpinner.NumberEditor(minReliableOperatingSpeedSpinner, "# %")); 1658 pa1.add(minReliableOperatingSpeedSpinner); 1659 minReliableOperatingSpeedSpinner.setToolTipText(Bundle.getMessage("MinReliableOperatingSpeedHint")); 1660 initiatePane.add(pa1); 1661 pa2.setLayout(new FlowLayout()); 1662 pa2.add(rampRateLabel); 1663 pa2.add(rampRateBox); 1664 rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint")); 1665 pa2.add(useSpeedProfileLabel); 1666 pa2.add(useSpeedProfileCheckBox); 1667 useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); 1668 initiatePane.add(pa2); 1669 pa2a.setLayout(new FlowLayout()); 1670 pa2a.add(stopBySpeedProfileLabel); 1671 pa2a.add(stopBySpeedProfileCheckBox); 1672 stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop 1673 pa2a.add(stopBySpeedProfileAdjustLabel); 1674 stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(5.0f), Float.valueOf(0.01f))); 1675 stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %")); 1676 pa2a.add(stopBySpeedProfileAdjustSpinner); 1677 stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint")); 1678 initiatePane.add(pa2a); 1679 pa3.setLayout(new FlowLayout()); 1680 pa3.add(soundDecoderBox); 1681 soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint")); 1682 pa3.add(new JLabel(" ")); 1683 pa3.add(runInReverseBox); 1684 runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint")); 1685 initiatePane.add(pa3); 1686 maxTrainLengthSpinner.setModel(new SpinnerNumberModel(Float.valueOf(18.0f), Float.valueOf(0.0f), Float.valueOf(10000.0f), Float.valueOf(0.5f))); 1687 maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0")); 1688 maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint")); // won't be updated while Dispatcher is open 1689 maxTrainLengthSpinner.addChangeListener(new ChangeListener() { 1690 @Override 1691 public void stateChanged(ChangeEvent e) { 1692 handlemaxTrainLengthChangeUnitsLength(e); 1693 } 1694 }); 1695 trainLengthUnitsComboBox.addActionListener(new ActionListener() { 1696 @Override 1697 public void actionPerformed(ActionEvent e) { 1698 handlemaxTrainLengthChangeUnitsLength(e); 1699 } 1700 }); 1701 trainLengthAltLengthLabel=new JLabel(); 1702 pa4.setLayout(new FlowLayout()); 1703 pa4.add(trainLengthLabel); 1704 pa4.add(maxTrainLengthSpinner); 1705 pa4.add(trainLengthUnitsComboBox); 1706 pa4.add(trainLengthAltLengthLabel); 1707 initiatePane.add(pa4); 1708 hideAutoRunItems(); // initialize with auto run items hidden 1709 } 1710 1711 private void handlemaxTrainLengthChangeUnitsLength(Object e) { 1712 trainLengthAltLengthLabel.setText(maxTrainLengthCalculateAltFormatted( 1713 ((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue(), 1714 (float) maxTrainLengthSpinner.getValue())); 1715 } 1716 1717 private String maxTrainLengthCalculateAltFormatted(TrainLengthUnits fromUnits, float fromValue) { 1718 float value = maxTrainLengthCalculateAlt(fromUnits, fromValue); 1719 switch (fromUnits) { 1720 case TRAINLENGTH_ACTUALINCHS: 1721 return String.format("%.2f %s", value, Bundle.getMessage("TrainLengthInScaleFeet")); 1722 case TRAINLENGTH_ACTUALCM: 1723 return String.format("%.1f %s", value, Bundle.getMessage("TrainLengthInScaleMeters")); 1724 case TRAINLENGTH_SCALEFEET: 1725 return String.format("%.1f %s", value, Bundle.getMessage("TrainLengthInActualInchs")); 1726 case TRAINLENGTH_SCALEMETERS: 1727 return String.format("%.0f %s", value, Bundle.getMessage("TrainLengthInActualcm")); 1728 default: 1729 log.error("Invalid TrainLengthUnits must have been updated, fix maxTrainLengthCalculateAltFormatted"); 1730 } 1731 return ""; 1732 } 1733 1734 private float maxTrainLengthToScaleMeters(TrainLengthUnits fromUnits, float fromValue) { 1735 float value; 1736 // convert to meters. 1737 switch (fromUnits) { 1738 case TRAINLENGTH_ACTUALINCHS: 1739 value = fromValue / 12.0f * (float) _dispatcher.getScale().getScaleRatio(); 1740 value = value / 3.28084f; 1741 break; 1742 case TRAINLENGTH_ACTUALCM: 1743 value = fromValue / 100.0f * (float) _dispatcher.getScale().getScaleRatio(); 1744 break; 1745 case TRAINLENGTH_SCALEFEET: 1746 value = fromValue / 3.28084f; 1747 break; 1748 case TRAINLENGTH_SCALEMETERS: 1749 value = fromValue; 1750 break; 1751 default: 1752 value = 0; 1753 log.error("Invalid TrainLengthUnits has been updated, fix me"); 1754 } 1755 return value; 1756 } 1757 1758 /* 1759 * Calculates the reciprocal unit. Actual to Scale and vice versa 1760 */ 1761 private float maxTrainLengthCalculateAlt(TrainLengthUnits fromUnits, float fromValue) { 1762 switch (fromUnits) { 1763 case TRAINLENGTH_ACTUALINCHS: 1764 // calc scale feet 1765 return (float) jmri.util.MathUtil.granulize(fromValue / 12 * (float) _dispatcher.getScale().getScaleRatio(),0.1f); 1766 case TRAINLENGTH_ACTUALCM: 1767 // calc scale meter 1768 return fromValue / 100 * (float) _dispatcher.getScale().getScaleRatio(); 1769 case TRAINLENGTH_SCALEFEET: 1770 // calc actual inchs 1771 return fromValue * 12 * (float) _dispatcher.getScale().getScaleFactor(); 1772 case TRAINLENGTH_SCALEMETERS: 1773 // calc actual cm. 1774 return fromValue * 100 * (float) _dispatcher.getScale().getScaleFactor(); 1775 default: 1776 log.error("Invalid TrainLengthUnits has been updated, fix me"); 1777 } 1778 return 0; 1779 } 1780 1781 private void hideAutoRunItems() { 1782 pa1.setVisible(false); 1783 pa2.setVisible(false); 1784 pa2a.setVisible(false); 1785 pa3.setVisible(false); 1786 pa4.setVisible(false); 1787 } 1788 1789 private void showAutoRunItems() { 1790 pa1.setVisible(true); 1791 pa2.setVisible(true); 1792 pa2a.setVisible(true); 1793 pa3.setVisible(true); 1794 pa4.setVisible(true); 1795 } 1796 1797 private void autoTrainInfoToDialog(TrainInfo info) { 1798 speedFactorSpinner.setValue(info.getSpeedFactor()); 1799 maxSpeedSpinner.setValue(info.getMaxSpeed()); 1800 minReliableOperatingSpeedSpinner.setValue(info.getMinReliableOperatingSpeed()); 1801 setComboBox(rampRateBox, info.getRampRate()); 1802 trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection()); 1803 runInReverseBox.setSelected(info.getRunInReverse()); 1804 soundDecoderBox.setSelected(info.getSoundDecoder()); 1805 trainLengthUnitsComboBox.setSelectedItemByValue(info.getTrainLengthUnits()); 1806 switch (info.getTrainLengthUnits()) { 1807 case TRAINLENGTH_SCALEFEET: 1808 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet()); 1809 break; 1810 case TRAINLENGTH_SCALEMETERS: 1811 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters()); 1812 break; 1813 case TRAINLENGTH_ACTUALINCHS: 1814 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet() * 12.0f * (float)_dispatcher.getScale().getScaleFactor()); 1815 break; 1816 case TRAINLENGTH_ACTUALCM: 1817 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters() * 100.0f * (float)_dispatcher.getScale().getScaleFactor()); 1818 break; 1819 default: 1820 maxTrainLengthSpinner.setValue(0.0f); 1821 } 1822 useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile()); 1823 stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile()); 1824 stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust()); 1825 if (autoRunBox.isSelected()) { 1826 showAutoRunItems(); 1827 } else { 1828 hideAutoRunItems(); 1829 } 1830 initiateFrame.pack(); 1831 } 1832 1833 private void autoRunItemsToTrainInfo(TrainInfo info) { 1834 info.setSpeedFactor((float) speedFactorSpinner.getValue()); 1835 info.setMaxSpeed((float) maxSpeedSpinner.getValue()); 1836 info.setMinReliableOperatingSpeed((float) minReliableOperatingSpeedSpinner.getValue()); 1837 info.setRampRate((String) rampRateBox.getSelectedItem()); 1838 info.setRunInReverse(runInReverseBox.isSelected()); 1839 info.setSoundDecoder(soundDecoderBox.isSelected()); 1840 info.setTrainLengthUnits(((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue()); 1841 info.setMaxTrainLengthScaleMeters(maxTrainLengthToScaleMeters( info.getTrainLengthUnits(), (float) maxTrainLengthSpinner.getValue())); 1842 1843 // Only use speed profile values if enabled 1844 if (useSpeedProfileCheckBox.isEnabled()) { 1845 info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected()); 1846 info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected()); 1847 info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue()); 1848 } else { 1849 info.setUseSpeedProfile(false); 1850 info.setStopBySpeedProfile(false); 1851 info.setStopBySpeedProfileAdjust(1.0f); 1852 } 1853 } 1854 1855 private void initializeRampCombo() { 1856 rampRateBox.removeAllItems(); 1857 rampRateBox.addItem(Bundle.getMessage("RAMP_NONE")); 1858 rampRateBox.addItem(Bundle.getMessage("RAMP_FAST")); 1859 rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM")); 1860 rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW")); 1861 rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW")); 1862 rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE")); 1863 // Note: the order above must correspond to the numbers in AutoActiveTrain.java 1864 } 1865 1866 /** 1867 * Sets up the RadioButtons and visability of spinner for the allocation method 1868 * 1869 * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any 1870 * other value the number of sections to allocate 1871 */ 1872 private void setAllocateMethodButtons(int value) { 1873 switch (value) { 1874 case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS: 1875 allocateBySafeRadioButton.setSelected(true); 1876 allocateCustomSpinner.setVisible(false); 1877 break; 1878 case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN: 1879 allocateAllTheWayRadioButton.setSelected(true); 1880 allocateCustomSpinner.setVisible(false); 1881 break; 1882 default: 1883 allocateNumberOfBlocks.setSelected(true); 1884 allocateCustomSpinner.setVisible(true); 1885 allocateCustomSpinner.setValue(value); 1886 } 1887 } 1888 1889 /* 1890 * ComboBox item. 1891 */ 1892 protected static class TrainDetectionItem { 1893 private String key; 1894 private TrainDetection value; 1895 public TrainDetectionItem(String text, TrainDetection trainDetection ) { 1896 this.key = text; 1897 this.value = trainDetection; 1898 } 1899 @Override 1900 public String toString() 1901 { 1902 return key; 1903 } 1904 public String getKey() 1905 { 1906 return key; 1907 } 1908 public TrainDetection getValue() 1909 { 1910 return value; 1911 } 1912 } 1913 1914 /* 1915 * ComboBox item. 1916 */ 1917 protected static class TrainLengthUnitsItem { 1918 private String key; 1919 private TrainLengthUnits value; 1920 public TrainLengthUnitsItem(String text, TrainLengthUnits trainLength ) { 1921 this.key = text; 1922 this.value = trainLength; 1923 } 1924 @Override 1925 public String toString() 1926 { 1927 return key; 1928 } 1929 public String getKey() 1930 { 1931 return key; 1932 } 1933 public TrainLengthUnits getValue() 1934 { 1935 return value; 1936 } 1937 } 1938 1939 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class); 1940 1941}