001package jmri.jmrit.logix; 002 003import java.awt.BorderLayout; 004import java.awt.Color; 005import java.awt.Component; 006import java.awt.Dimension; 007import java.awt.FontMetrics; 008import java.awt.event.*; 009import java.awt.MouseInfo; 010import java.awt.Point; 011import java.awt.Rectangle; 012import java.util.ArrayList; 013import java.util.List; 014import java.util.ListIterator; 015 016import javax.annotation.CheckForNull; 017import javax.annotation.Nonnull; 018 019import javax.swing.*; 020import javax.swing.table.*; 021import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 022 023import jmri.InstanceManager; 024import jmri.NamedBean; 025import jmri.NamedBeanHandle; 026import jmri.SpeedStepMode; 027import jmri.jmrit.picker.PickListModel; 028import jmri.util.ThreadingUtil; 029import jmri.jmrit.logix.ThrottleSetting.Command; 030import jmri.jmrit.logix.ThrottleSetting.CommandValue; 031import jmri.jmrit.logix.ThrottleSetting.ValueType; 032import jmri.util.swing.JmriJOptionPane; 033 034/** 035 * WarrantFame creates and edits Warrants <br> 036 * <hr> 037 * This file is part of JMRI. 038 * <p> 039 * JMRI is free software; you can redistribute it and/or modify it under the 040 * terms of version 2 of the GNU General Public License as published by the Free 041 * Software Foundation. See the "COPYING" file for a copy of this license. 042 * <p> 043 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 044 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 045 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 046 * 047 * @author Pete Cressman Copyright (C) 2009, 2010 048 */ 049public class WarrantFrame extends WarrantRoute { 050 051 private int _rowHeight; 052 private Warrant _warrant; // unregistered warrant - may be a copy of a 053 // registered warrant 054 private Warrant _saveWarrant; 055 private ThrottleTableModel _commandModel; 056 private JTable _commandTable; 057 private JScrollPane _throttlePane; 058 private Dimension _viewPortDim; 059 060 private ArrayList<ThrottleSetting> _throttleCommands = new ArrayList<>(); 061 private long _startTime; 062 private float _speedFactor; 063 private float _speed; 064 private long _TTP = 0; 065 private boolean _forward = true; 066 private LearnThrottleFrame _learnThrottle = null; 067 private static Color myGreen = new Color(0, 100, 0); 068 069 private JTextField _sysNameBox; 070 private JTextField _userNameBox; 071 072 private JTabbedPane _tabbedPane; 073 private JPanel _routePanel; 074 private JPanel _commandPanel; 075 private JPanel _parameterPanel; 076 private final JRadioButton _isSCWarrant = new JRadioButton(Bundle.getMessage("SmallLayoutTrainAutomater"), false); 077 private final JRadioButton _isWarrant = new JRadioButton(Bundle.getMessage("NormalWarrant"), true); 078 private DisplayButton _speedUnits; 079 private JLabel _unitsLabel; 080 private float _speedConversion; 081 private final JCheckBox _runForward = new JCheckBox(Bundle.getMessage("Forward")); 082 private final JFormattedTextField _speedFactorTextField = new JFormattedTextField(); 083 private final JFormattedTextField _TTPtextField = new JFormattedTextField(); 084 private final JCheckBox _noRampBox = new JCheckBox(); 085 private final JCheckBox _shareRouteBox = new JCheckBox(); 086 private final JCheckBox _addTracker = new JCheckBox(); 087 private final JCheckBox _haltStartBox = new JCheckBox(); 088 private final JCheckBox _runETOnlyBox = new JCheckBox(); 089 private final JRadioButton _invisible = new JRadioButton(); 090 private final JTextField _statusBox = new JTextField(90); 091 private final JRadioButton _showRoute = new JRadioButton(Bundle.getMessage("showRoute"), false); 092 private final JRadioButton _showScript = new JRadioButton(Bundle.getMessage("showScript"), false); 093 094 private final JTextField _searchStatus = new JTextField(); 095 private boolean _dirty = false; 096 097 /** 098 * Constructor for opening an existing warrant for editing. 099 * @param w the Warrant to edit. 100 */ 101 protected WarrantFrame(@Nonnull Warrant w) { 102 super(); 103 // w is registered 104 _saveWarrant = w; 105 // temp unregistered version until editing is saved. 106 _warrant = new Warrant(w.getSystemName(), w.getUserName()); 107 setup(_saveWarrant, false); 108 init(); 109 if ( _saveWarrant instanceof SCWarrant) { 110 _isSCWarrant.setSelected(true); 111 _showRoute.setSelected(true); 112 showCommands(false); 113 //setPanelEnabled(buttonPanel, false); 114 } 115 } 116 117 /** 118 * Constructor for creating a new warrant or copy or concatenation of 119 * warrants. 120 * Called by WarrantTableAction. 121 * @param startW the Warrant to Copy or Concatenate. 122 * @param endW the other Warrant to Concatenate with. 123 */ 124 protected WarrantFrame(@CheckForNull Warrant startW, @CheckForNull Warrant endW) { 125 super(); 126 WarrantManager mgr = InstanceManager.getDefault(WarrantManager.class); 127 String sName = mgr.getAutoSystemName(); 128 while (mgr.getBySystemName(sName) != null) { 129 mgr.updateAutoNumber(sName); 130 sName = mgr.getAutoSystemName(); 131 } 132 _warrant = new Warrant(sName, null); 133 if (startW != null) { 134 if (endW != null) { // concatenate warrants 135 WarrantTableFrame tf = WarrantTableFrame.getDefault(); 136 tf.setVisible(true); 137 boolean includeAllCmds = tf.askStopQuestion(startW.getLastOrder().getBlock().getDisplayName()); 138 /* 139 if (JmriJOptionPane.showConfirmDialog(f, Bundle.getMessage("stopAtBlock", 140 startW.getLastOrder().getBlock().getDisplayName()), 141 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 142 JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION) { 143 includeAllCmds = true; 144 }*/ 145 float entranceSpeed = setup(startW, !includeAllCmds); 146 List<BlockOrder> orders = endW.getBlockOrders(); 147 BlockOrder bo = orders.get(0); // block order of common midblock 148 bo.setExitName(endW.getfirstOrder().getExitName()); 149 for (int i = 1; i < orders.size(); i++) { 150 _orders.add(new BlockOrder(orders.get(i))); 151 } 152 _destination.setOrder(endW.getLastOrder()); 153 if (_via.getOrder() == null) { 154 _via.setOrder(endW.getViaOrder()); 155 } 156 if (_avoid.getOrder() == null) { 157 _avoid.setOrder(endW.getAvoidOrder()); 158 } 159 float exitSpeed = 0; 160 NamedBean bean = bo.getBlock(); // common block 161 for (ThrottleSetting ts : endW.getThrottleCommands()) { 162 if (includeAllCmds) { 163 _throttleCommands.add(new ThrottleSetting(ts)); 164 } else { 165 Command cmd = ts.getCommand(); 166 if (cmd.equals(Command.SPEED)) { 167 exitSpeed = ts.getValue().getFloat(); 168 } else if (cmd.equals(Command.NOOP) && !ts.getBean().equals(bean)) { 169 includeAllCmds = true; 170 long et = _speedUtil.getTimeForDistance(entranceSpeed, bo.getPathLength()) / 2; 171 RampData ramp = _speedUtil.getRampForSpeedChange(entranceSpeed, exitSpeed); 172 String blockName = bean.getDisplayName(); 173 if (ramp.isUpRamp()) { 174 ListIterator<Float> iter = ramp.speedIterator(true); 175 while (iter.hasNext()) { 176 float speedSetting = iter.next(); 177 _throttleCommands.add(new ThrottleSetting(et, Command.SPEED, -1, ValueType.VAL_FLOAT, 178 SpeedStepMode.UNKNOWN, speedSetting, "", blockName, _speedUtil.getTrackSpeed(speedSetting))); 179 et = ramp.getRampTimeIncrement(); 180 } 181 } else { 182 ListIterator<Float> iter = ramp.speedIterator(false); 183 while (iter.hasPrevious()) { 184 float speedSetting = iter.previous(); 185 _throttleCommands.add(new ThrottleSetting(et, Command.SPEED, -1, ValueType.VAL_FLOAT, 186 SpeedStepMode.UNKNOWN, speedSetting, "", blockName, _speedUtil.getTrackSpeed(speedSetting))); 187 et = ramp.getRampTimeIncrement(); 188 } 189 } 190 _throttleCommands.add(new ThrottleSetting(ts)); 191 } 192 } 193 } 194 } else { // else just copy startW 195 setup(startW, false); 196 } 197 } // else create new warrant 198 init(); 199 } 200 201 /** 202 * Set up parameters from an existing warrant. note that _warrant is 203 * unregistered. 204 */ 205 private float setup(@Nonnull Warrant warrant, boolean omitLastBlockCmds) { 206 _origin.setOrder(warrant.getfirstOrder()); 207 _destination.setOrder(warrant.getLastOrder()); 208 _via.setOrder(warrant.getViaOrder()); 209 _avoid.setOrder(warrant.getAvoidOrder()); 210 List<BlockOrder> list = warrant.getBlockOrders(); 211 _orders = new ArrayList<>(list.size()); 212 for (BlockOrder bo : list) { 213 _orders.add(new BlockOrder(bo)); 214 } 215 216 if (warrant instanceof SCWarrant) { 217 _speedFactor = ((SCWarrant) warrant).getSpeedFactor(); 218 _TTP = ((SCWarrant) warrant).getTimeToPlatform(); 219 _forward = ((SCWarrant) warrant).getForward(); 220 } 221 222 float entranceSpeed = 0; 223 for (ThrottleSetting ts : warrant.getThrottleCommands()) { 224 if (omitLastBlockCmds && !list.isEmpty()) { 225 NamedBean bean = list.get(list.size()-1).getBlock(); 226 Command cmd = ts.getCommand(); 227 if (cmd.equals(Command.SPEED)) { 228 entranceSpeed = ts.getValue().getFloat(); 229 } 230 _throttleCommands.add(new ThrottleSetting(ts)); 231 if (cmd.equals(Command.NOOP) && ts.getBean().equals(bean)) { 232 break; 233 } 234 } else { 235 _throttleCommands.add(new ThrottleSetting(ts)); 236 } 237 } 238 _shareRouteBox.setSelected(warrant.getShareRoute()); 239 _warrant.setShareRoute(warrant.getShareRoute()); 240 _addTracker.setSelected(warrant.getAddTracker()); 241 _warrant.setAddTracker(warrant.getAddTracker()); 242 _haltStartBox.setSelected(warrant.getHaltStart()); 243 _warrant.setHaltStart(warrant.getHaltStart()); 244 _noRampBox.setSelected(warrant.getNoRamp()); 245 _warrant.setNoRamp(warrant.getNoRamp()); 246 _runETOnlyBox.setSelected(warrant.getRunBlind()); 247 _warrant.setRunBlind(warrant.getRunBlind()); 248 setTrainName(warrant.getTrainName()); 249 _warrant.setTrainName(warrant.getTrainName()); 250 251 SpeedUtil spU = warrant.getSpeedUtil(); 252 setSpeedUtil(_warrant.getSpeedUtil()); 253 _speedUtil.setDccAddress(spU.getDccAddress()); 254 _speedUtil.setRosterId(spU.getRosterId()); 255 if (_speedUtil.getDccAddress() != null) { 256 setTrainInfo(warrant.getTrainName()); 257 } else { 258 setTrainName(warrant.getTrainName()); 259 } 260 return entranceSpeed; 261 } 262 263 private void init() { 264 _commandModel = new ThrottleTableModel(); 265 266 JPanel contentPane = new JPanel(); 267 contentPane.setLayout(new BorderLayout(5, 5)); 268 269 contentPane.add(makeTopPanel(), BorderLayout.NORTH); 270 271 _tabbedPane = new JTabbedPane(); 272 _tabbedPane.addTab(Bundle.getMessage("MakeRoute"), makeFindRouteTabPanel()); 273 _tabbedPane.addTab(Bundle.getMessage("RecordPlay"), makeSetPowerTabPanel()); 274 contentPane.add(_tabbedPane, BorderLayout.CENTER); 275 276 contentPane.add(makeEditableButtonPanel(), BorderLayout.SOUTH); 277 if (_orders != null && !_orders.isEmpty()) { 278 _tabbedPane.setSelectedIndex(1); 279 } 280 if (!_throttleCommands.isEmpty()) { 281 _showScript.setSelected(true); 282 } 283 setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); 284 addWindowListener(new java.awt.event.WindowAdapter() { 285 @Override 286 public void windowClosing(java.awt.event.WindowEvent e) { 287 if (askClose()) { 288 WarrantTableAction.getDefault().closeWarrantFrame(); 289 } 290 } 291 }); 292 293 makeMenus(); 294 setTitle(Bundle.getMessage("editing", _warrant.getDisplayName())); 295 setContentPane(contentPane); 296 setVisible(true); 297 _parameterPanel.setMaximumSize(_parameterPanel.getPreferredSize()); 298 _dirty = false; 299 pack(); 300 getContentPane().addComponentListener(new ComponentAdapter() { 301 @Override 302 public void componentResized(ComponentEvent e) { 303 Component c = (Component) e.getSource(); 304 int height = c.getHeight(); 305 _viewPortDim.height = (_rowHeight * 10) + height - 541; 306 _throttlePane.getViewport().setPreferredSize(_viewPortDim); 307 _throttlePane.invalidate(); 308 _commandTable.invalidate(); 309 } 310 }); 311 speedUnitsAction(); 312 } 313 314 public boolean askClose() { 315 if (_dirty) { 316 // if runMode != MODE_NONE, this is probably a panic shutdown. Don't 317 // halt it. 318 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("saveOrClose", _warrant.getDisplayName()), 319 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 320 JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION) { 321 if (!isRunning()) { 322 save(); 323 } 324 } 325 } 326 _dirty = false; 327 return true; 328 } 329 330 private JPanel makeTopPanel() { 331 JPanel topPanel = new JPanel(); 332 topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS)); 333 334 JPanel panel = new JPanel(); 335 panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); 336 panel.add(Box.createHorizontalStrut(2 * STRUT_SIZE)); 337 JLabel sysNameLabel = new JLabel(Bundle.getMessage("LabelSystemName")); 338 panel.add( sysNameLabel ); 339 panel.add(Box.createHorizontalStrut(STRUT_SIZE)); 340 if (_saveWarrant != null) { 341 _sysNameBox = new JTextField(_saveWarrant.getSystemName()); 342 _sysNameBox.setEditable(false); 343 _userNameBox = new JTextField(_saveWarrant.getUserName()); 344 } else { 345 _sysNameBox = new JTextField(_warrant.getSystemName()); 346 _userNameBox = new JTextField(_warrant.getUserName()); 347 } 348 sysNameLabel.setLabelFor(_sysNameBox); 349 _sysNameBox.setBackground(Color.white); 350 panel.add(_sysNameBox); 351 352 panel.add(Box.createHorizontalStrut(2 * STRUT_SIZE)); 353 JLabel userNameLabel = new JLabel(Bundle.getMessage("LabelUserName")); 354 userNameLabel.setLabelFor( _userNameBox ); 355 panel.add( userNameLabel ); 356 panel.add(Box.createHorizontalStrut(STRUT_SIZE)); 357 panel.add( _userNameBox ); 358 359 panel.add(Box.createHorizontalStrut(2 * STRUT_SIZE)); 360 topPanel.add(panel); 361 topPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 362 363 return topPanel; 364 } 365 366 private JPanel makeFindRouteTabPanel() { 367 JPanel tab1 = new JPanel(); 368 tab1.setLayout(new BoxLayout(tab1, BoxLayout.LINE_AXIS)); 369 tab1.add(Box.createHorizontalStrut(STRUT_SIZE)); 370 371 JPanel topLeft = new JPanel(); 372 topLeft.setLayout(new BoxLayout(topLeft, BoxLayout.PAGE_AXIS)); 373 374 topLeft.add(makeBlockPanels(false)); 375 376 topLeft.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 377 tab1.add(topLeft); 378 379 tab1.add(Box.createHorizontalStrut(STRUT_SIZE)); 380 JPanel topRight = new JPanel(); 381 topRight.setLayout(new BoxLayout(topRight, BoxLayout.LINE_AXIS)); 382 383 JPanel panel = new JPanel(); 384 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 385 panel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 386 panel.add(calculatePanel(true)); 387 panel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 388 panel.add(searchDepthPanel(true)); 389 390 JPanel p = new JPanel(); 391 p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); 392 p.add(makeTextBoxPanel(true, _searchStatus, "SearchRoute", null)); 393 _searchStatus.setEditable(false); 394 p.add(Box.createVerticalGlue()); 395 panel.add(p); 396 397 _searchStatus.setBackground(Color.white); 398 _searchStatus.setEditable(false); 399 panel.add(Box.createRigidArea(new Dimension(10, 400 topLeft.getPreferredSize().height - panel.getPreferredSize().height))); 401 panel.add(Box.createVerticalStrut(STRUT_SIZE)); 402 panel.add(Box.createVerticalGlue()); 403 topRight.add(panel); 404 topRight.add(Box.createHorizontalStrut(STRUT_SIZE)); 405 406 PickListModel<OBlock> pickListModel = PickListModel.oBlockPickModelInstance(); 407 topRight.add(new JScrollPane(pickListModel.makePickTable())); 408 Dimension dim = topRight.getPreferredSize(); 409 topRight.setMinimumSize(dim); 410 tab1.add(topRight); 411 tab1.add(Box.createHorizontalStrut(STRUT_SIZE)); 412 return tab1; 413 } 414 415 private JPanel makeSetPowerTabPanel() { 416 JPanel tab2 = new JPanel(); 417 tab2.setLayout(new BoxLayout(tab2, BoxLayout.PAGE_AXIS)); 418 tab2.add(makeTabMidPanel()); 419 420 _parameterPanel = new JPanel(); 421 _parameterPanel.setLayout(new BoxLayout(_parameterPanel, BoxLayout.LINE_AXIS)); 422 423 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 424 _parameterPanel.add(makeBorderedTrainPanel()); 425 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 426 JPanel typePanel = makeTypePanel(); 427 JPanel edge = new JPanel(); 428 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 429 Bundle.getMessage("SelectType"), 430 javax.swing.border.TitledBorder.CENTER, 431 javax.swing.border.TitledBorder.TOP)); 432 edge.add(typePanel); 433 _parameterPanel.add(edge); 434 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 435 436 JPanel scParamPanel = makeSCParamPanel(); 437 edge = new JPanel(); 438 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 439 Bundle.getMessage("SetSCParameters"), 440 javax.swing.border.TitledBorder.CENTER, 441 javax.swing.border.TitledBorder.TOP)); 442 edge.add(scParamPanel); 443 _parameterPanel.add(edge); 444 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 445 446 JPanel learnPanel = makeRecordPanel(); 447 edge = new JPanel(); 448 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 449 Bundle.getMessage("LearnMode"), 450 javax.swing.border.TitledBorder.CENTER, 451 javax.swing.border.TitledBorder.TOP)); 452 edge.add(learnPanel); 453 _parameterPanel.add(edge); 454 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 455 456 JPanel paramsPanel = makeRunParmsPanel(); 457 edge = new JPanel(); 458 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 459 Bundle.getMessage("RunParameters"), 460 javax.swing.border.TitledBorder.CENTER, 461 javax.swing.border.TitledBorder.TOP)); 462 edge.add(paramsPanel); 463 _parameterPanel.add(edge); 464 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 465 466 JPanel runPanel = makePlaybackPanel(); 467 edge = new JPanel(); 468 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 469 Bundle.getMessage("RunTrain"), 470 javax.swing.border.TitledBorder.CENTER, 471 javax.swing.border.TitledBorder.TOP)); 472 edge.add(runPanel); 473 _parameterPanel.add(edge); 474 _parameterPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 475 _parameterPanel.setPreferredSize(_parameterPanel.getPreferredSize()); 476 tab2.add(_parameterPanel); 477 478 _isSCWarrant.addActionListener((ActionEvent e) -> { 479 setPanelEnabled(scParamPanel, true); 480 setPanelEnabled(learnPanel, false); 481 setPanelEnabled(paramsPanel, false); 482 setPanelEnabled(runPanel, false); 483 }); 484 if ( _saveWarrant instanceof SCWarrant) { 485 setPanelEnabled(scParamPanel, true); 486 setPanelEnabled(learnPanel, false); 487 setPanelEnabled(paramsPanel, false); 488 setPanelEnabled(runPanel, false); 489 _isSCWarrant.setVisible(true); 490 } 491 492 _isWarrant.addActionListener((ActionEvent e) -> { 493 setPanelEnabled(scParamPanel, false); 494 setPanelEnabled(learnPanel, true); 495 setPanelEnabled(paramsPanel, true); 496 setPanelEnabled(runPanel, true); 497 }); 498 499 JPanel panel = new JPanel(); 500 panel.add(makeTextBoxPanel(false, _statusBox, "Status", null)); 501 _statusBox.setEditable(false); 502 _statusBox.setMinimumSize(new Dimension(300, _statusBox.getPreferredSize().height)); 503 _statusBox.setMaximumSize(new Dimension(900, _statusBox.getPreferredSize().height)); 504 panel.add(_statusBox); 505 tab2.add(panel); 506 507 return tab2; 508 } 509 510 private void setPanelEnabled(@Nonnull JPanel panel, Boolean isEnabled) { 511 panel.setEnabled(isEnabled); 512 513 Component[] components = panel.getComponents(); 514 515 for (Component component : components) { 516 if ( component == null ) { 517 continue; 518 } 519 if ( component instanceof JPanel ) { 520 setPanelEnabled((JPanel) component, isEnabled); 521 } 522 component.setEnabled(isEnabled); 523 } 524 } 525 526 private JPanel makeBorderedTrainPanel() { 527 JPanel trainPanel = makeTrainIdPanel(null); 528 529 JPanel edge = new JPanel(); 530 edge.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 531 Bundle.getMessage("SetPower"), 532 javax.swing.border.TitledBorder.CENTER, 533 javax.swing.border.TitledBorder.TOP)); 534 edge.add(trainPanel); 535 return edge; 536 } 537 538 private JPanel makeTypePanel() { 539 JPanel typePanel = new JPanel(); 540 typePanel.setLayout(new BoxLayout(typePanel, BoxLayout.LINE_AXIS)); 541 typePanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 542 543 JPanel wTypePanel = new JPanel(); 544 wTypePanel.setLayout(new BoxLayout(wTypePanel, BoxLayout.PAGE_AXIS)); 545 wTypePanel.add(Box.createVerticalStrut(STRUT_SIZE)); 546 ButtonGroup group = new ButtonGroup(); 547 group.add(_isSCWarrant); 548 group.add(_isWarrant); 549 _isSCWarrant.setToolTipText(Bundle.getMessage("SCW_Tooltip")); 550 _isWarrant.setToolTipText(Bundle.getMessage("W_Tooltip")); 551 wTypePanel.add(_isSCWarrant); 552 wTypePanel.add(_isWarrant); 553 typePanel.add(wTypePanel); 554 return typePanel; 555 } 556 557 private void addSpeeds() { 558 float speed = 0.0f; 559 for (ThrottleSetting ts : _throttleCommands) { 560 CommandValue cmdVal = ts.getValue(); 561 ValueType valType = cmdVal.getType(); 562 switch (valType) { 563 case VAL_FLOAT: 564 speed = _speedUtil.getTrackSpeed(cmdVal.getFloat()); 565 break; 566 case VAL_TRUE: 567 _speedUtil.setIsForward(true); 568 break; 569 case VAL_FALSE: 570 _speedUtil.setIsForward(false); 571 break; 572 default: 573 } 574 ts.setTrackSpeed(speed); 575 } 576 _commandModel.fireTableDataChanged(); 577 showCommands(true); 578 } 579 580 private JPanel makeSCParamPanel() { 581 JPanel scParamPanel = new JPanel(); 582 scParamPanel.setLayout(new BoxLayout(scParamPanel, BoxLayout.PAGE_AXIS)); 583 scParamPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 584 585 scParamPanel.add(_runForward); 586 _runForward.setSelected(_forward); 587 588 JPanel ttpPanel = new JPanel(); 589 ttpPanel.setLayout(new BoxLayout(ttpPanel, BoxLayout.LINE_AXIS)); 590 JLabel ttp_l = new JLabel(Bundle.getMessage("TTP")); 591 _TTPtextField.setValue(_TTP); 592 _TTPtextField.setColumns(6); 593 ttp_l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 594 _TTPtextField.setAlignmentX(JComponent.RIGHT_ALIGNMENT); 595 ttpPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 596 ttpPanel.add(ttp_l); 597 ttpPanel.add(_TTPtextField); 598 ttpPanel.setToolTipText(Bundle.getMessage("TTPtoolTip")); 599 scParamPanel.add(ttpPanel); 600 601 JPanel sfPanel = new JPanel(); 602 sfPanel.setLayout(new BoxLayout(sfPanel, BoxLayout.LINE_AXIS)); 603 JLabel sf_l = new JLabel(Bundle.getMessage("SF")); 604 _speedFactorTextField.setValue((long) (100 * _speedFactor)); 605 _speedFactorTextField.setColumns(3); 606 sf_l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 607 _speedFactorTextField.setAlignmentX(JComponent.RIGHT_ALIGNMENT); 608 sfPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 609 sfPanel.add(sf_l); 610 sfPanel.add(_speedFactorTextField); 611 sfPanel.setToolTipText(Bundle.getMessage("sfToolTip")); 612 scParamPanel.add(sfPanel); 613 614 if (_isWarrant.isSelected()) { 615 setPanelEnabled(scParamPanel, false); 616 } 617 return scParamPanel; 618 } 619 620 private JPanel makeRecordPanel() { 621 JPanel learnPanel = new JPanel(); 622 learnPanel.setLayout(new BoxLayout(learnPanel, BoxLayout.LINE_AXIS)); 623 learnPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 624 625 JPanel startStopPanel = new JPanel(); 626 startStopPanel.setLayout(new BoxLayout(startStopPanel, BoxLayout.PAGE_AXIS)); 627 startStopPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 628 JButton startButton = new JButton(Bundle.getMessage("Start")); 629 startButton.addActionListener((ActionEvent e) -> { 630 clearTempWarrant(); 631 _tabbedPane.setSelectedIndex(1); 632 showCommands(true); 633 runLearnModeTrain(); 634 }); 635 JButton stopButton = new JButton(Bundle.getMessage("Stop")); 636 stopButton.addActionListener((ActionEvent e) -> { 637 stopRunTrain(false); 638 }); 639 startButton.setAlignmentX(JComponent.CENTER_ALIGNMENT); 640 stopButton.setAlignmentX(JComponent.CENTER_ALIGNMENT); 641 startStopPanel.add(startButton); 642 startStopPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 643 startStopPanel.add(stopButton); 644 startStopPanel.add(Box.createRigidArea(new Dimension(30 + stopButton.getPreferredSize().width, 10))); 645 learnPanel.add(startStopPanel); 646 647 return learnPanel; 648 } 649 650 private JPanel makeRunParmsPanel() { 651 JPanel paramsPanel = new JPanel(); 652 paramsPanel.setLayout(new BoxLayout(paramsPanel, BoxLayout.LINE_AXIS)); 653 paramsPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 654 655 JPanel panel = new JPanel(); 656 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 657 panel.add(Box.createVerticalStrut(STRUT_SIZE)); 658 panel.add(makeTextBoxPanel(_shareRouteBox, "ShareRoute", "ToolTipShareRoute")); 659 panel.add(makeTextBoxPanel(_addTracker, "AddTracker", "ToolTipAddTracker")); 660 panel.add(makeTextBoxPanel(_noRampBox, "NoRamping", "ToolTipNoRamping")); 661 panel.add(makeTextBoxPanel(_haltStartBox, "HaltAtStart", null)); 662 panel.add(makeTextBoxPanel(_runETOnlyBox, "RunETOnly", "ToolTipRunETOnly")); 663 664 paramsPanel.add(panel); 665 return paramsPanel; 666 } 667 668 private JPanel makePlaybackPanel() { 669 JPanel runPanel = new JPanel(); 670 runPanel.setLayout(new BoxLayout(runPanel, BoxLayout.LINE_AXIS)); 671 runPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 672 673 JPanel panel = new JPanel(); 674 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 675 runPanel.add(panel); 676 runPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 677 678 JRadioButton run = new JRadioButton(Bundle.getMessage("ARun"), false); 679 JRadioButton halt = new JRadioButton(Bundle.getMessage("Stop"), false); 680 JRadioButton resume = new JRadioButton(Bundle.getMessage("Resume"), false); 681 JRadioButton eStop = new JRadioButton(Bundle.getMessage("EStop"), false); 682 JRadioButton abort = new JRadioButton(Bundle.getMessage("Abort"), false); 683 684 panel = new JPanel(); 685 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 686 ButtonGroup group = new ButtonGroup(); 687 group.add(run); 688 group.add(halt); 689 group.add(resume); 690 group.add(eStop); 691 group.add(abort); 692 group.add(_invisible); 693 panel.add(run); 694 panel.add(halt); 695 panel.add(resume); 696 panel.add(eStop); 697 panel.add(abort); 698 runPanel.add(panel); 699 700 run.addActionListener((ActionEvent e) -> { 701 runTrain(); 702 }); 703 halt.addActionListener((ActionEvent e) -> { 704 doControlCommand(Warrant.HALT); 705 }); 706 resume.addActionListener((ActionEvent e) -> { 707 doControlCommand(Warrant.RESUME); 708 }); 709 eStop.addActionListener((ActionEvent e) -> { 710 doControlCommand(Warrant.ESTOP); 711 }); 712 abort.addActionListener((ActionEvent e) -> { 713 doControlCommand(Warrant.ABORT); 714 }); 715 runPanel.add(panel); 716 return runPanel; 717 } 718 719 private JPanel makeTabMidPanel() { 720 JPanel midPanel = new JPanel(); 721 midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.PAGE_AXIS)); 722 723 JPanel tablePanel = new JPanel(); 724 tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.LINE_AXIS)); 725 tablePanel.add(Box.createHorizontalStrut(5)); 726 _routePanel = makeRouteTablePanel(); 727 tablePanel.add(_routePanel); 728 tablePanel.add(makeThrottleTablePanel()); 729 JPanel buttonPanel = new JPanel(); 730 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); 731 ButtonGroup group = new ButtonGroup(); 732 group.add(_showRoute); 733 group.add(_showScript); 734 buttonPanel.add(_showRoute); 735 buttonPanel.add(_showScript); 736 boolean show = (!_throttleCommands.isEmpty()); 737 showCommands(show); 738 _showScript.setSelected(show); 739 _showRoute.addActionListener((ActionEvent e) -> { 740 showCommands(false); 741 }); 742 _showScript.addActionListener((ActionEvent e) -> { 743 showCommands(true); 744 }); 745 746 if (_saveWarrant != null && _saveWarrant instanceof SCWarrant) { 747 _showRoute.setSelected(true); 748 showCommands(false); 749 setPanelEnabled(buttonPanel, false); 750 } 751 _isSCWarrant.addActionListener((ActionEvent e) -> { 752 _showRoute.setSelected(true); 753 showCommands(false); 754 setPanelEnabled(buttonPanel, false); 755 }); 756 _isWarrant.addActionListener((ActionEvent e) -> { 757 setPanelEnabled(buttonPanel, true); 758 }); 759 760 midPanel.add(buttonPanel); 761 midPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 762 midPanel.add(tablePanel); 763 midPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 764 765 return midPanel; 766 } 767 768 private void showCommands(boolean setCmds) { 769 _routePanel.setVisible(!setCmds); 770 _commandPanel.setVisible(setCmds); 771 } 772 773 private void speedUnitsAction() { 774 switch (_displayPref) { 775 case MPH: 776 _displayPref = Display.KPH; 777 _speedConversion = _scale * 3.6f; 778 setFormatter("kph"); 779 break; 780 case KPH: 781 _displayPref = Display.MMPS; 782 _speedConversion = 1000; 783 _unitsLabel.setText(Bundle.getMessage("trackSpeed")); 784 setFormatter("mmps"); 785 break; 786 case MMPS: 787 _displayPref = Display.INPS; 788 _speedConversion = 39.37f; 789 setFormatter("inps"); 790 break; 791 case INPS: 792 default: 793 _displayPref = Display.MPH; 794 _speedConversion = 2.23694f * _scale; 795 _unitsLabel.setText(Bundle.getMessage("scaleSpeed")); 796 setFormatter("mph"); 797 break; 798 } 799 _speedUnits.setDisplayPref(_displayPref); 800 addSpeeds(); 801 } 802 803 private void setFormatter(String title) { 804 JTableHeader header = _commandTable.getTableHeader(); 805 TableColumnModel colMod = header.getColumnModel(); 806 TableColumn tabCol = colMod.getColumn(ThrottleTableModel.SPEED_COLUMN); 807 tabCol.setHeaderValue(Bundle.getMessage(title)); 808 header.repaint(); 809 } 810 811 private JPanel makeThrottleTablePanel() { 812 _commandTable = new JTable(_commandModel); 813 DefaultCellEditor ed = (DefaultCellEditor) _commandTable.getDefaultEditor(String.class); 814 ed.setClickCountToStart(1); 815 816 TableColumnModel columnModel = _commandTable.getColumnModel(); 817 for (int i = 0; i < _commandModel.getColumnCount(); i++) { 818 int width = _commandModel.getPreferredWidth(i); 819 columnModel.getColumn(i).setPreferredWidth(width); 820 } 821 TableColumn cmdColumn = columnModel.getColumn(ThrottleTableModel.COMMAND_COLUMN); 822 cmdColumn.setCellEditor(new CommandCellEditor(new JComboBox<>())); 823 cmdColumn.setCellRenderer(new CommandCellRenderer()); 824 cmdColumn.setMinWidth(40); 825 826 TableColumn valueColumn = columnModel.getColumn(ThrottleTableModel.VALUE_COLUMN); 827 valueColumn.setCellEditor(new ValueCellEditor(new JTextField())); 828 829 _throttlePane = new JScrollPane(_commandTable); 830 _viewPortDim = _commandTable.getPreferredSize(); 831 _rowHeight = _commandTable.getRowHeight(); 832 _viewPortDim.height = _rowHeight * 10; 833 _throttlePane.getViewport().setPreferredSize(_viewPortDim); 834 835 JPanel buttonPanel = new JPanel(); 836 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS)); 837 buttonPanel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 838 839 JButton insertButton = new JButton(Bundle.getMessage("buttonInsertRow")); 840 insertButton.addActionListener((ActionEvent e) -> { 841 insertRow(); 842 }); 843 buttonPanel.add(insertButton); 844 buttonPanel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 845 846 JButton deleteButton = new JButton(Bundle.getMessage("buttonDeleteRow")); 847 deleteButton.addActionListener((ActionEvent e) -> { 848 deleteRow(); 849 }); 850 buttonPanel.add(deleteButton); 851 buttonPanel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 852 853 if (_displayPref.equals(Display.MMPS) || _displayPref.equals(Display.INPS)) { 854 _unitsLabel = new JLabel(Bundle.getMessage("trackSpeed")); 855 } else { 856 _unitsLabel = new JLabel(Bundle.getMessage("scaleSpeed")); 857 } 858 _unitsLabel.setHorizontalAlignment(SwingConstants.CENTER); 859 860 _speedUnits = new DisplayButton(_displayPref); 861 FontMetrics fm = _speedUnits.getFontMetrics(_speedUnits.getFont()); 862 int width = Math.max(fm.stringWidth(Display.KPH.toString()), 863 Math.max(fm.stringWidth(Display.MPH.toString()), 864 fm.stringWidth(Display.MMPS.toString()))); 865 Dimension d = _speedUnits.getPreferredSize(); 866 d.width = width + 40; 867 _speedUnits.setMaximumSize(d); 868 _speedUnits.setMinimumSize(d); 869 _speedUnits.setPreferredSize(d); 870 _speedUnits.addActionListener((ActionEvent evt) -> speedUnitsAction()); 871 872 buttonPanel.add(_unitsLabel); 873 buttonPanel.add(_speedUnits); 874 875 _commandPanel = new JPanel(); 876 _commandPanel.setLayout(new BoxLayout(_commandPanel, BoxLayout.PAGE_AXIS)); 877 JLabel title = new JLabel(Bundle.getMessage("CommandTableTitle")); 878 JPanel panel = new JPanel(); 879 panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); 880 JPanel p = new JPanel(); 881 p.add(_throttlePane); 882 panel.add(p); 883 buttonPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 884 panel.add(buttonPanel); 885 buttonPanel.add(Box.createHorizontalStrut(STRUT_SIZE)); 886 _commandPanel.add(title); 887 _commandPanel.add(panel); 888 _commandPanel.add(Box.createGlue()); 889 _displayPref = Display.KPH; 890 return _commandPanel; 891 } 892 893 private void insertRow() { 894 int row = _commandTable.getSelectedRow(); 895 if (row < 0) { 896 showWarning(Bundle.getMessage("selectRow")); 897 return; 898 } 899 row++; 900 _throttleCommands.add(row, new ThrottleSetting()); 901 _commandModel.fireTableDataChanged(); 902 _commandTable.setRowSelectionInterval(row, row); 903 } 904 905 private void deleteRow() { 906 int row = _commandTable.getSelectedRow(); 907 if (row < 0) { 908 showWarning(Bundle.getMessage("selectRow")); 909 return; 910 } 911 ThrottleSetting cmd = _throttleCommands.get(row); 912 if (cmd != null && cmd.getCommand() != null) { 913 if (cmd.getCommand().equals(Command.NOOP)) { 914 showWarning(Bundle.getMessage("cannotDeleteNoop")); 915 return; 916 } 917 long time = cmd.getTime(); 918 if ((row + 1) < _throttleCommands.size()) { 919 time += _throttleCommands.get(row + 1).getTime(); 920 _throttleCommands.get(row + 1).setTime(time); 921 } 922 } 923 _throttleCommands.remove(row); 924 _dirty = true; 925 _commandModel.fireTableDataChanged(); 926 } 927 928 /** 929 * Save, Cancel, Delete buttons 930 */ 931 private JPanel makeEditableButtonPanel() { 932 JPanel buttonPanel = new JPanel(); 933 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); 934 buttonPanel.add(Box.createHorizontalStrut(10 * STRUT_SIZE)); 935 936 JPanel panel = new JPanel(); 937 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 938 JButton saveButton = new JButton(Bundle.getMessage("ButtonSave")); 939 saveButton.addActionListener((ActionEvent e) -> { 940 if (save()) { 941 WarrantTableAction.getDefault().closeWarrantFrame(); 942 } 943 }); 944 panel.add(saveButton); 945 panel.add(Box.createVerticalStrut(STRUT_SIZE)); 946 buttonPanel.add(panel); 947 buttonPanel.add(Box.createHorizontalStrut(3 * STRUT_SIZE)); 948 949 panel = new JPanel(); 950 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 951 JButton copyButton = new JButton(Bundle.getMessage("ButtonCopy")); 952 copyButton.addActionListener((ActionEvent e) -> { 953 WarrantTableAction.getDefault().makeWarrantFrame(_saveWarrant, null); 954 }); 955 panel.add(copyButton); 956 panel.add(Box.createVerticalStrut(STRUT_SIZE)); 957 buttonPanel.add(panel); 958 buttonPanel.add(Box.createHorizontalStrut(3 * STRUT_SIZE)); 959 960 panel = new JPanel(); 961 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 962 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 963 cancelButton.addActionListener((ActionEvent e) -> { 964 close(); 965 }); 966 panel.add(cancelButton); 967 panel.add(Box.createVerticalStrut(STRUT_SIZE)); 968 buttonPanel.add(panel); 969 buttonPanel.add(Box.createHorizontalStrut(3 * STRUT_SIZE)); 970 971 buttonPanel.add(Box.createHorizontalGlue()); 972 return buttonPanel; 973 } 974 975 private void doControlCommand(int cmd) { 976 if (log.isDebugEnabled()) { 977 log.debug("actionPerformed on doControlCommand cmd= {}", cmd); 978 } 979 int runMode = _warrant.getRunMode(); 980 if (runMode == Warrant.MODE_NONE) { 981 JmriJOptionPane.showMessageDialog(this, 982 Bundle.getMessage("NotRunning", _warrant.getDisplayName()), 983 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 984 } else if (runMode == Warrant.MODE_LEARN && cmd != Warrant.ABORT) { 985 JmriJOptionPane.showMessageDialog(this, 986 Bundle.getMessage("LearnInvalidControl", _warrant.getDisplayName()), 987 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 988 } else { 989 _warrant.controlRunTrain(cmd); 990 } 991 _invisible.setSelected(true); 992 } 993 994 private void makeMenus() { 995 setTitle(Bundle.getMessage("TitleWarrant", _warrant.getDisplayName())); 996 JMenuBar menuBar = new JMenuBar(); 997 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 998 fileMenu.add(new jmri.configurexml.StoreMenu()); 999 menuBar.add(fileMenu); 1000 setJMenuBar(menuBar); 1001 addHelpMenu("package.jmri.jmrit.logix.CreateEditWarrant", true); 1002 } 1003 1004 private void clearCommands() { 1005 _throttleCommands = new ArrayList<>(); 1006 _commandModel.fireTableDataChanged(); 1007 _searchStatus.setText(""); 1008 } 1009 1010 @Override 1011 protected void selectedRoute(ArrayList<BlockOrder> orders) { 1012 clearCommands(); 1013 _tabbedPane.setSelectedIndex(1); 1014 } 1015 1016 /** 1017 * Sets address and block orders and does checks Non-null return is fatal 1018 */ 1019 private String checkTrainId() { 1020 String msg = setAddress(); // sets SpeedUtil address in 'this' 1021 // (WarrantRoute) 1022 if (msg == null) { 1023 msg = routeIsValid(); 1024 } 1025 if (msg == null) { 1026 _warrant.setBlockOrders(getOrders()); 1027 msg = _warrant.checkforTrackers(); 1028 } 1029 if (msg == null) { 1030 msg = checkLocoAddress(); 1031 } 1032 return msg; 1033 } 1034 1035 private String checkThrottleCommands() { 1036 if (_throttleCommands.size() <= getOrders().size() + 1) { 1037 return Bundle.getMessage("NoCommands", _warrant.getDisplayName()); 1038 } 1039 float lastSpeed = 0.0f; 1040 for (int i = 0; i < _throttleCommands.size(); i++) { 1041 ThrottleSetting ts = _throttleCommands.get(i); 1042 Command cmd = ts.getCommand(); 1043 CommandValue val = ts.getValue(); 1044 if (val == null || cmd == null) { 1045 return Bundle.getMessage("BadThrottleSetting", i + 1); 1046 } 1047 ValueType valType = val.getType(); 1048 if (valType == null) { 1049 return Bundle.getMessage("BadThrottleSetting", i + 1); 1050 } 1051 switch (cmd) { 1052 case SPEED: 1053 if (valType != ValueType.VAL_FLOAT) { 1054 return Bundle.getMessage("badThrottleCommand", 1055 i + 1, cmd.toString(), valType.toString()); 1056 } 1057 lastSpeed = ts.getValue().getFloat(); 1058 if (lastSpeed > 1) { 1059 return Bundle.getMessage("badSpeed", lastSpeed); 1060 } else if (lastSpeed < 0) { // EStop OK only in the last 1061 // block 1062 OBlock blk = getOrders().get(getOrders().size() - 1).getBlock(); 1063 if ( !blk.getSystemName().equals(ts.getBeanSystemName())) { 1064 return Bundle.getMessage("badSpeed", lastSpeed); 1065 } 1066 } 1067 break; 1068 case NOOP: 1069 if (valType != ValueType.VAL_NOOP) { 1070 return Bundle.getMessage("badThrottleCommand", 1071 i + 1, cmd.toString(), valType.toString()); 1072 } 1073 break; 1074 case FORWARD: 1075 if (valType != ValueType.VAL_TRUE && valType != ValueType.VAL_FALSE) { 1076 return Bundle.getMessage("badThrottleCommand", 1077 i + 1, cmd.toString(), valType.toString()); 1078 } 1079 break; 1080 case FKEY: 1081 case LATCHF: 1082 if (valType != ValueType.VAL_ON && valType != ValueType.VAL_OFF) { 1083 return Bundle.getMessage("badThrottleCommand", 1084 i + 1, cmd.toString(), valType.toString()); 1085 } 1086 break; 1087 case SET_SENSOR: 1088 case WAIT_SENSOR: 1089 if (valType != ValueType.VAL_ACTIVE && valType != ValueType.VAL_INACTIVE) { 1090 return Bundle.getMessage("badThrottleCommand", 1091 i + 1, cmd.toString(), valType.toString()); 1092 } 1093 String msg = ts.getBeanDisplayName(); 1094 if (msg == null) { 1095 return Bundle.getMessage("badThrottleCommand", 1096 i + 1, cmd.toString(), valType.toString()); 1097 } 1098 msg = WarrantFrame.checkBeanName(cmd, ts.getBeanDisplayName()); 1099 if (msg != null) { 1100 return msg + 1101 '\n' + 1102 Bundle.getMessage("badThrottleCommand", 1103 i + 1, cmd.toString(), valType.toString()); 1104 } 1105 break; 1106 case RUN_WARRANT: 1107 if (valType != ValueType.VAL_INT) { 1108 return Bundle.getMessage("badThrottleCommand", 1109 i + 1, cmd.toString(), valType.toString()); 1110 } 1111 msg = ts.getBeanDisplayName(); 1112 if (msg == null) { 1113 return Bundle.getMessage("badThrottleCommand", 1114 i + 1, cmd.toString(), valType.toString()); 1115 } 1116 msg = WarrantFrame.checkBeanName(cmd, ts.getBeanDisplayName()); 1117 if (msg != null) { 1118 return msg + 1119 '\n' + 1120 Bundle.getMessage("badThrottleCommand", 1121 i + 1, cmd.toString(), valType.toString()); 1122 } 1123 break; 1124 case SPEEDSTEP: 1125 if (valType != ValueType.VAL_STEP) { 1126 return Bundle.getMessage("badThrottleCommand", 1127 i + 1, cmd.toString(), valType.toString()); 1128 } 1129 break; 1130 case SET_MEMORY: 1131 if (valType != ValueType.VAL_TEXT) { 1132 return Bundle.getMessage("badThrottleCommand", 1133 i + 1, cmd.toString(), valType.toString()); 1134 } 1135 msg = ts.getBeanDisplayName(); 1136 if (msg == null) { 1137 return Bundle.getMessage("badThrottleCommand", 1138 i + 1, cmd.toString(), valType.toString()); 1139 } 1140 msg = WarrantFrame.checkBeanName(cmd, ts.getBeanDisplayName()); 1141 if (msg != null) { 1142 return msg + 1143 '\n' + 1144 Bundle.getMessage("badThrottleCommand", 1145 i + 1, cmd.toString(), valType.toString()); 1146 } 1147 break; 1148 default: 1149 return Bundle.getMessage("BadThrottleSetting", i + 1); 1150 } 1151 } 1152 if (lastSpeed > 0.0f) { 1153 return Bundle.getMessage("BadLastSpeed", lastSpeed); 1154 } 1155 return null; 1156 } 1157 1158 static String checkBeanName(Command command, String beanName) { 1159 switch (command) { 1160 case SET_SENSOR: 1161 case WAIT_SENSOR: 1162 if (InstanceManager.sensorManagerInstance().getSensor(beanName) == null) { 1163 return Bundle.getMessage("BadSensor", beanName); 1164 } 1165 break; 1166 case RUN_WARRANT: 1167 if (InstanceManager.getDefault(WarrantManager.class).getWarrant(beanName) == null) { 1168 return Bundle.getMessage("BadWarrant", beanName); 1169 } 1170 break; 1171 case SET_MEMORY: 1172 if (InstanceManager.getDefault(jmri.MemoryManager.class).getMemory(beanName) == null) { 1173 return Bundle.getMessage("BadMemory", beanName); 1174 } 1175 break; 1176 default: 1177 if (InstanceManager.getDefault(OBlockManager.class).getOBlock(beanName) == null) { 1178 return Bundle.getMessage("BlockNotFound", beanName); 1179 } 1180 break; 1181 } 1182 return null; 1183 } 1184 1185 private void runLearnModeTrain() { 1186 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1187 String msg = null; 1188 if (isRunning()) { 1189 msg = Bundle.getMessage("CannotRun", _warrant.getDisplayName(), 1190 Bundle.getMessage("TrainRunning", _warrant.getTrainName())); 1191 } 1192 if (msg == null) { 1193 _warrant.setBlockOrders(getOrders()); 1194 msg = checkTrainId(); 1195 } 1196 if (msg == null) { 1197 msg = _warrant.checkRoute(); 1198 } 1199 if (msg == null) { 1200 msg = WarrantTableFrame.getDefault().getModel().checkAddressInUse(_warrant); 1201 } 1202 if (msg == null) { 1203 msg = _warrant.allocateRoute(false, getOrders()); 1204 } 1205 toFront(); 1206 1207 if (msg != null) { 1208 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LearnError", msg), 1209 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1210 _warrant.deAllocate(); 1211 setStatus(msg, Color.red); 1212 return; 1213 } 1214 1215 if (!_throttleCommands.isEmpty()) { 1216 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("deleteCommand"), 1217 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 1218 JmriJOptionPane.QUESTION_MESSAGE) != JmriJOptionPane.YES_OPTION ) { 1219 return; 1220 } 1221 _throttleCommands = new ArrayList<>(); 1222 _commandModel.fireTableDataChanged(); 1223 } 1224 1225 msg = _warrant.checkStartBlock(); 1226 if (msg != null) { 1227 if (msg.equals("warnStart")) { 1228 msg = Bundle.getMessage("warnStart", getTrainName(), _warrant.getCurrentBlockName()); 1229 JmriJOptionPane.showMessageDialog(this, msg, 1230 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1231 setStatus(msg, Color.red); 1232 return; 1233 } else if (msg.equals("BlockDark")) { 1234 msg = Bundle.getMessage("BlockDark", _warrant.getCurrentBlockName(), getTrainName()); 1235 if (JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog(this, 1236 Bundle.getMessage("OkToRun", msg), Bundle.getMessage("QuestionTitle"), 1237 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.WARNING_MESSAGE)) { 1238 stopRunTrain(true); 1239 setStatus(msg, Color.red); 1240 return; 1241 } 1242 } 1243 setStatus(msg, Color.black); 1244 } 1245 1246 if (_learnThrottle == null) { 1247 _learnThrottle = new LearnThrottleFrame(this); 1248 } else { 1249 _learnThrottle.setVisible(true); 1250 } 1251 1252 _warrant.setTrainName(getTrainName()); 1253 _startTime = System.currentTimeMillis(); 1254 _speed = 0.0f; 1255 1256 _warrant.addPropertyChangeListener(this); 1257 1258 msg = _warrant.setRunMode(Warrant.MODE_LEARN, _speedUtil.getDccAddress(), _learnThrottle, 1259 _throttleCommands, _runETOnlyBox.isSelected()); 1260 if (msg != null) { 1261 stopRunTrain(true); 1262 JmriJOptionPane.showMessageDialog(this, msg, Bundle.getMessage("WarningTitle"), 1263 JmriJOptionPane.WARNING_MESSAGE); 1264 setStatus(msg, Color.red); 1265 } 1266 } 1267 1268 private long lastClicktime; // keep double clicks from showing dialogs 1269 1270 protected void runTrain() { 1271 long time = System.currentTimeMillis(); 1272 if (time - lastClicktime < 1000) { 1273 return; 1274 } 1275 lastClicktime = time; 1276 1277 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1278 String msg = null; 1279 if (isRunning()) { 1280 msg = Bundle.getMessage("CannotRun", _warrant.getDisplayName(), 1281 Bundle.getMessage("TrainRunning", _warrant.getTrainName())); 1282 } 1283 if (msg == null) { 1284 _warrant.setTrainName(getTrainName()); 1285 _warrant.setShareRoute(_shareRouteBox.isSelected()); 1286 _warrant.setAddTracker(_addTracker.isSelected()); 1287 _warrant.setHaltStart(_haltStartBox.isSelected()); 1288 _warrant.setNoRamp(_noRampBox.isSelected()); 1289 } 1290 if (msg == null) { 1291 msg = checkTrainId(); 1292 } 1293 if (msg == null) { 1294 msg = checkThrottleCommands(); 1295 if (msg == null && !_warrant.hasRouteSet() && _runETOnlyBox.isSelected()) { 1296 msg = Bundle.getMessage("BlindRouteNotSet", _warrant.getDisplayName()); 1297 } 1298 } 1299 if (msg == null) { 1300 WarrantTableModel model = WarrantTableFrame.getDefault().getModel(); 1301 msg = model.checkAddressInUse(_warrant); 1302 } 1303 1304 if (msg != null) { 1305 JmriJOptionPane.showMessageDialog(this, msg, Bundle.getMessage("WarningTitle"), 1306 JmriJOptionPane.WARNING_MESSAGE); 1307 1308 setStatus(msg, Color.black); 1309 return; 1310 } 1311 if (_warrant.getRunMode() != Warrant.MODE_NONE) { 1312 return; 1313 } 1314 _warrant.addPropertyChangeListener(this); 1315 1316 msg = _warrant.setRunMode(Warrant.MODE_RUN, _speedUtil.getDccAddress(), null, 1317 _throttleCommands, _runETOnlyBox.isSelected()); 1318 if (msg != null) { 1319 clearWarrant(); 1320 JmriJOptionPane.showMessageDialog(this, msg, 1321 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1322 setStatus(msg, Color.red); 1323 return; 1324 } 1325 1326 msg = _warrant.checkStartBlock(); 1327 if (msg != null) { 1328 if (msg.equals("warnStart")) { 1329 msg = Bundle.getMessage("warnStart", _warrant.getTrainName(), _warrant.getCurrentBlockName()); 1330 } else if (msg.equals("BlockDark")) { 1331 msg = Bundle.getMessage("BlockDark", _warrant.getCurrentBlockName(), _warrant.getTrainName()); 1332 } 1333 if (JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog(this, 1334 Bundle.getMessage("OkToRun", msg), Bundle.getMessage("QuestionTitle"), 1335 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.WARNING_MESSAGE)) { 1336 clearWarrant(); 1337 setStatus(msg, Color.red); 1338 } else { 1339 setStatus(_warrant.getRunningMessage(), myGreen); 1340 } 1341 } 1342 } 1343 1344 /* 1345 * Stop a MODE_LEARN warrant, i.e. non-registered member _warrant 1346 */ 1347 private void stopRunTrain(boolean aborted) { 1348 if (_learnThrottle != null) { 1349 _learnThrottle.dispose(); 1350 _learnThrottle = null; 1351 } 1352 if (_warrant == null) { 1353 return; 1354 } 1355 1356 if (_warrant.getRunMode() == Warrant.MODE_LEARN) { 1357 List<BlockOrder> orders = getOrders(); 1358 if (orders != null && orders.size() > 1) { 1359 BlockOrder bo = _warrant.getCurrentBlockOrder(); 1360 if (bo != null) { 1361 OBlock lastBlock = orders.get(orders.size() - 1).getBlock(); 1362 OBlock currentBlock = bo.getBlock(); 1363 if (!lastBlock.equals(currentBlock)) { 1364 if ((lastBlock.getState() & OBlock.UNDETECTED) != 0 && 1365 currentBlock.equals(orders.get(orders.size() - 2).getBlock())) { 1366 setThrottleCommand("NoOp", Bundle.getMessage("Mark"), lastBlock.getDisplayName()); 1367 setStatus(Bundle.getMessage("LearningStop"), myGreen); 1368 } else if (!aborted) { 1369 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("IncompleteScript", lastBlock), 1370 Bundle.getMessage("WarningTitle"), 1371 JmriJOptionPane.WARNING_MESSAGE); 1372 } 1373 } else { 1374 setStatus(Bundle.getMessage("LearningStop"), myGreen); 1375 } 1376 } 1377 } 1378 } 1379 clearWarrant(); 1380 } 1381 1382 private void clearWarrant() { 1383 if (_warrant != null) { 1384 _warrant.stopWarrant(false, true); 1385 _warrant.removePropertyChangeListener(this); 1386 } 1387 } 1388 1389 protected Warrant getWarrant() { 1390 return _warrant; 1391 } 1392 1393 private void setStatus(String msg, Color c) { 1394 ThreadingUtil.runOnGUIEventually(() -> { 1395 _statusBox.setForeground(c); 1396 _statusBox.setText(msg); 1397 }); 1398 } 1399 1400 @Override 1401 protected void maxThrottleEventAction() { 1402 } 1403 1404 /** 1405 * Property names from Warrant: "runMode" - from setRunMode "controlChange" 1406 * - from controlRunTrain "blockChange" - from goingActive "allocate" - from 1407 * allocateRoute, deAllocate "setRoute" - from setRoute, goingActive 1408 * Property names from Engineer: "Command" - from run "SpeedRestriction" - 1409 * ThrottleRamp run Property names from RouteFinder: "RouteSearch" - from 1410 * run 1411 */ 1412 @Override 1413 public void propertyChange(java.beans.PropertyChangeEvent e) { 1414 String property = e.getPropertyName(); 1415 if (property.equals("DnDrop")) { 1416 doAction(e.getSource()); 1417 } else if (e.getSource() instanceof Warrant && _warrant.equals(e.getSource())) { 1418 if (log.isDebugEnabled()) { 1419 log.debug("propertyChange \"{}\" old= {} new= {} source= {}", 1420 property, e.getOldValue(), e.getNewValue(), e.getSource().getClass().getName()); 1421 } 1422 String msg = null; 1423 Color color = myGreen; 1424 switch (_warrant.getRunMode()) { 1425 case Warrant.MODE_NONE: 1426 _warrant.removePropertyChangeListener(this); 1427 if (property.equals("StopWarrant")) { 1428 String blkName = (String) e.getOldValue(); 1429 String bundleKey = (String) e.getNewValue(); 1430 if (blkName == null) { 1431 msg = Bundle.getMessage(bundleKey, 1432 _warrant.getTrainName(), _warrant.getDisplayName()); 1433 color = Color.red; 1434 } else { 1435 msg = Bundle.getMessage(bundleKey, 1436 _warrant.getTrainName(), _warrant.getDisplayName(), 1437 blkName); 1438 color = myGreen; 1439 } 1440 } 1441 break; 1442 case Warrant.MODE_LEARN: 1443 switch (property) { 1444 case "blockChange": 1445 OBlock oldBlock = (OBlock) e.getOldValue(); 1446 OBlock newBlock = (OBlock) e.getNewValue(); 1447 if (newBlock == null) { 1448 stopRunTrain(true); 1449 msg = Bundle.getMessage("ChangedRoute", 1450 _warrant.getTrainName(), 1451 oldBlock.getDisplayName(), 1452 _warrant.getDisplayName()); 1453 color = Color.red; 1454 } else { 1455 setThrottleCommand("NoOp", Bundle.getMessage("Mark"), 1456 ((OBlock) e.getNewValue()).getDisplayName()); 1457 msg = Bundle.getMessage("TrackerBlockEnter", 1458 _warrant.getTrainName(), 1459 newBlock.getDisplayName()); 1460 } 1461 break; 1462 case "abortLearn": 1463 stopRunTrain(true); 1464 int oldIdx = ((Integer) e.getOldValue()); 1465 int newIdx = ((Integer) e.getNewValue()); 1466 if (oldIdx > newIdx) { 1467 msg = Bundle.getMessage("LearnAbortOccupied", 1468 _warrant.getBlockAt(oldIdx), 1469 _warrant.getDisplayName()); 1470 color = Color.red; 1471 } else { 1472 msg = Bundle.getMessage("warrantAbort", 1473 _warrant.getTrainName(), 1474 _warrant.getDisplayName()); 1475 color = Color.red; 1476 } 1477 break; 1478 default: 1479 msg = Bundle.getMessage("Learning", _warrant.getCurrentBlockName()); 1480 color = Color.black; 1481 break; 1482 } 1483 break; 1484 case Warrant.MODE_RUN: 1485 case Warrant.MODE_MANUAL: 1486 if (e.getPropertyName().equals("blockChange")) { 1487 OBlock oldBlock = (OBlock) e.getOldValue(); 1488 OBlock newBlock = (OBlock) e.getNewValue(); 1489 if (newBlock == null) { 1490 msg = Bundle.getMessage("ChangedRoute", 1491 _warrant.getTrainName(), 1492 oldBlock.getDisplayName(), 1493 _warrant.getDisplayName()); 1494 color = Color.red; 1495 } else { 1496 msg = Bundle.getMessage("TrackerBlockEnter", 1497 _warrant.getTrainName(), 1498 newBlock.getDisplayName()); 1499 } 1500 } else if (e.getPropertyName().equals("ReadyToRun")) { 1501 msg = _warrant.getRunningMessage(); 1502 } else if (e.getPropertyName().equals("SpeedChange")) { 1503 msg = _warrant.getRunningMessage(); 1504 color = Color.black; 1505 } else if (property.equals("SignalOverrun")) { 1506 String name = (String) e.getOldValue(); 1507 String speed = (String) e.getNewValue(); 1508 msg = Bundle.getMessage("SignalOverrun", 1509 _warrant.getTrainName(), speed, name); 1510 color = Color.red; 1511 } else if (property.equals("OccupyOverrun")) { 1512 String blockName = (String) e.getOldValue(); 1513 OBlock occuppier = (OBlock) e.getNewValue(); 1514 msg = Bundle.getMessage("OccupyOverrun", 1515 _warrant.getTrainName(), blockName, occuppier); 1516 color = Color.red; 1517 } else if (property.equals("WarrantOverrun")) { 1518 String blkName = (String) e.getOldValue(); 1519 OBlock warName = (OBlock) e.getNewValue(); 1520 msg = Bundle.getMessage("WarrantOverrun", 1521 _warrant.getTrainName(), blkName, warName); 1522 color = Color.red; 1523 } else if (e.getPropertyName().equals("WarrantStart")) { 1524 msg = Bundle.getMessage("warrantStart", 1525 _warrant.getTrainName(), _warrant.getDisplayName(), 1526 _warrant.getCurrentBlockName()); 1527 if (_warrant.getState() == Warrant.HALT) { 1528 JmriJOptionPane.showMessageDialog(this, _warrant.getRunningMessage(), 1529 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1530 } 1531 } else if (e.getPropertyName().equals("controlChange")) { 1532 int newCntrl = ((Integer) e.getNewValue()); 1533 msg = Bundle.getMessage("controlChange", 1534 _warrant.getTrainName(), 1535 Bundle.getMessage(Warrant.CNTRL_CMDS[newCntrl]), 1536 _warrant.getCurrentBlockName()); 1537 color = Color.black; 1538 } else if (e.getPropertyName().equals("throttleFail")) { 1539 msg = Bundle.getMessage("ThrottleFail", 1540 _warrant.getTrainName(), e.getNewValue()); 1541 color = Color.red; 1542 } else { 1543 return; 1544 } 1545 break; 1546 default: 1547 } 1548 setStatus(msg, color); 1549 } 1550 invalidate(); 1551 } 1552 1553 protected void setThrottleCommand(String cmd, String value) { 1554 String bName = Bundle.getMessage("NoBlock"); 1555 BlockOrder bo = _warrant.getCurrentBlockOrder(); 1556 if (bo != null) { 1557 bName = bo.getBlock().getDisplayName(); 1558 } 1559 /* 1560 * if (cmd.equals("Forward")) { 1561 * _speedUtil.setIsForward(Boolean.parseBoolean(value)); } 1562 */ 1563 setThrottleCommand(cmd, value, bName); 1564 } 1565 1566 protected void setSpeedCommand(float speed) { 1567 if (_warrant.getSpeedUtil().profileHasSpeedInfo()) { 1568 _speed = _warrant.getSpeedUtil().getTrackSpeed(speed); // mm/ms 1569 } else { 1570 _speed = 0.0f; 1571 } 1572 setThrottleCommand("speed", Float.toString(speed)); 1573 } 1574 1575 private void setThrottleCommand(String cmd, String value, String bName) { 1576 long endTime = System.currentTimeMillis(); 1577 long time = endTime - _startTime; 1578 _startTime = endTime; 1579 ThrottleSetting ts = new ThrottleSetting(time, cmd, value, bName, _speed); 1580 log.debug("setThrottleCommand= {}", ts); 1581 _throttleCommands.add(ts); 1582 _commandModel.fireTableDataChanged(); 1583 1584 scrollCommandTable(_commandModel.getRowCount()); 1585 } 1586 1587 private void scrollCommandTable(int row) { 1588 JScrollBar bar = _throttlePane.getVerticalScrollBar(); 1589 bar.setValue(row * _rowHeight); 1590 bar.invalidate(); 1591 } 1592 1593 /** 1594 * Called by WarrantTableAction before closing the editing of this warrant 1595 * 1596 * @return true if this warrant or its pre-editing version is running 1597 */ 1598 protected boolean isRunning() { 1599 return _warrant._runMode != Warrant.MODE_NONE || 1600 (_saveWarrant != null && _saveWarrant._runMode != Warrant.MODE_NONE); 1601 } 1602 1603 /** 1604 * Verify that commands are correct 1605 * 1606 * @return true if commands are OK 1607 */ 1608 private boolean save() { 1609 boolean fatal = false; 1610 String msg = null; 1611 if (isRunning()) { 1612 msg = Bundle.getMessage("CannotEdit", _warrant.getDisplayName()); 1613 } 1614 if (msg == null) { 1615 msg = routeIsValid(); 1616 } 1617 if (msg != null) { 1618 msg = Bundle.getMessage("SaveError", msg); 1619 fatal = true; 1620 } 1621 if (msg == null) { 1622 msg = checkLocoAddress(); 1623 } 1624 if (msg == null && !_isSCWarrant.isSelected()) { 1625 msg = checkThrottleCommands(); 1626 if (msg != null) { 1627 msg = Bundle.getMessage("BadData", msg); 1628 fatal = true; 1629 } 1630 } 1631 1632 WarrantManager mgr = InstanceManager.getDefault(WarrantManager.class); 1633 if (msg == null) { 1634 if (_saveWarrant != null) { 1635 if ((_saveWarrant instanceof SCWarrant && !_isSCWarrant.isSelected()) || 1636 (!(_saveWarrant instanceof SCWarrant) && _isSCWarrant.isSelected())) { 1637 // _saveWarrant already registered, but is not the correct 1638 // class. 1639 mgr.deregister(_saveWarrant); 1640 _warrant = mgr.createNewWarrant( 1641 _sysNameBox.getText(), _userNameBox.getText(), _isSCWarrant.isSelected(), 1642 (long) _TTPtextField.getValue()); 1643 } else { 1644 String uName = _userNameBox.getText(); 1645 if (uName.length() > 0 && 1646 !uName.equals(_saveWarrant.getUserName()) && 1647 mgr.getWarrant(uName) != null) { 1648 fatal = true; 1649 msg = Bundle.getMessage("WarrantExists", _userNameBox.getText()); 1650 } else { 1651 _warrant = _saveWarrant; // update registered warrant 1652 } 1653 } 1654 } else { 1655 if (_warrant == null) { 1656 _warrant = mgr.createNewWarrant( 1657 _sysNameBox.getText(), _userNameBox.getText(), 1658 _isSCWarrant.isSelected(), (long) _TTPtextField.getValue()); 1659 } 1660 } 1661 } 1662 if (_warrant == null) { // find out why 1663 if (_userNameBox.getText().length() > 0 && mgr.getByUserName(_userNameBox.getText()) != null) { 1664 msg = Bundle.getMessage("WarrantExists", _userNameBox.getText()); 1665 } else if (mgr.getBySystemName(_sysNameBox.getText()) != null) { 1666 msg = Bundle.getMessage("WarrantExists", _sysNameBox.getText()); 1667 } else { 1668 msg = Bundle.getMessage("IWSystemName", _sysNameBox.getText()); 1669 } 1670 fatal = true; 1671 } 1672 if (msg == null && _userNameBox.getText().length() == 0) { 1673 msg = Bundle.getMessage("NoUserName", _sysNameBox.getText()); 1674 } 1675 if (msg != null) { 1676 if (fatal) { 1677 JmriJOptionPane.showMessageDialog(this, msg, 1678 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1679 return false; 1680 } 1681 int result = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("SaveQuestion", msg), 1682 Bundle.getMessage("QuestionTitle"), 1683 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE); 1684 if (result != JmriJOptionPane.YES_OPTION ) { 1685 if (_warrant != null) { 1686 mgr.deregister(_warrant); 1687 } 1688 return false; 1689 } 1690 } 1691 1692 if (_saveWarrant != null) { 1693 _warrant = _saveWarrant; 1694 if ((_saveWarrant instanceof SCWarrant && !_isSCWarrant.isSelected()) || 1695 (!(_saveWarrant instanceof SCWarrant) && _isSCWarrant.isSelected())) { 1696 // _saveWarrant already registered, but is not the correct class. 1697 InstanceManager.getDefault(WarrantManager.class).deregister(_saveWarrant); 1698 _warrant = InstanceManager.getDefault(WarrantManager.class).createNewWarrant( 1699 _sysNameBox.getText(), _userNameBox.getText(), _isSCWarrant.isSelected(), (long)_TTPtextField.getValue()); 1700 } 1701 } else { 1702 _warrant = InstanceManager.getDefault(WarrantManager.class).createNewWarrant( 1703 _sysNameBox.getText(), _userNameBox.getText(), _isSCWarrant.isSelected(), (long)_TTPtextField.getValue()); 1704 } 1705 1706 if (_isSCWarrant.isSelected()) { 1707 ((SCWarrant) _warrant).setForward(_runForward.isSelected()); 1708 ((SCWarrant) _warrant).setTimeToPlatform((long) _TTPtextField.getValue()); 1709 long sf = (long) _speedFactorTextField.getValue(); 1710 float sf_float = sf; 1711 ((SCWarrant) _warrant).setSpeedFactor(sf_float / 100); 1712 } 1713 _warrant.setTrainName(getTrainName()); 1714 _warrant.setRunBlind(_runETOnlyBox.isSelected()); 1715 _warrant.setShareRoute(_shareRouteBox.isSelected()); 1716 _warrant.setAddTracker(_addTracker.isSelected()); 1717 _warrant.setNoRamp(_noRampBox.isSelected()); 1718 _warrant.setHaltStart(_haltStartBox.isSelected()); 1719 _warrant.setUserName(_userNameBox.getText()); 1720 1721 _warrant.setViaOrder(getViaBlockOrder()); 1722 _warrant.setAvoidOrder(getAvoidBlockOrder()); 1723 _warrant.setBlockOrders(getOrders()); 1724 _warrant.setThrottleCommands(_throttleCommands); 1725 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1726 if (_saveWarrant == null) { 1727 try { 1728 mgr.register(_warrant); 1729 } catch (jmri.NamedBean.DuplicateSystemNameException dsne) { 1730 // ignore 1731 } 1732 _saveWarrant = _warrant; 1733 } 1734 1735 if (log.isDebugEnabled()) { 1736 log.debug("warrant {} saved _train {} name= {}", 1737 _warrant.getDisplayName(), _speedUtil.getRosterId(), getTrainName()); 1738 } 1739 WarrantTableAction.getDefault().updateWarrantMenu(); 1740 WarrantTableFrame.getDefault().getModel().fireTableDataChanged(); 1741 _dirty = false; 1742 return true; 1743 } 1744 1745 protected List<ThrottleSetting> getThrottleCommands() { 1746 return _throttleCommands; 1747 } 1748 1749 protected void close() { 1750 _dirty = false; 1751 clearTempWarrant(); 1752 if (_warrant.getRunMode() != Warrant.MODE_NONE) { 1753 stopRunTrain(true); 1754 } 1755 closeProfileTable(); 1756 dispose(); 1757 } 1758 1759 // =============== Throttle Command Table ==========================\\ 1760 // =============== VALUE_COLUMN editing/rendering ==================\\ 1761 1762 static final String[] TRUE_FALSE = {ValueType.VAL_TRUE.toString(), ValueType.VAL_FALSE.toString()}; 1763 static final String[] ON_OFF = {ValueType.VAL_ON.toString(), ValueType.VAL_OFF.toString()}; 1764 static final String[] SENSOR_STATES = {ValueType.VAL_ACTIVE.toString(), ValueType.VAL_INACTIVE.toString()}; 1765 1766 private class ValueCellEditor extends DefaultCellEditor { 1767 1768 private ComboDialog editorDialog; 1769 private TextDialog textDialog; 1770 private String currentText; 1771 1772 ValueCellEditor(JTextField textField) { 1773 super(textField); 1774 setClickCountToStart(1); 1775 log.debug("valueCellEditor Ctor"); 1776 } 1777 1778 @Override 1779 public Component getTableCellEditorComponent(JTable table, Object value, 1780 boolean isSelected, int row, int col) { 1781 log.debug("getValueCellEditorComponent: row= {}, column= {} selected = {} value= {}", 1782 row, col, isSelected, value); 1783 currentText = value.toString(); 1784 editorComponent = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, col); 1785 Command cmd = (Command) _commandModel.getValueAt(row, ThrottleTableModel.COMMAND_COLUMN); 1786 Rectangle cellRect = table.getCellRect(row, col, false); 1787 Dimension dim = new Dimension(cellRect.width, cellRect.height); 1788 1789 if (cmd == null) { 1790 showTextDialog(dim); 1791 } else { 1792 switch (cmd) { 1793 case FORWARD: 1794 showComboDialog(TRUE_FALSE, dim); 1795 break; 1796 case FKEY: 1797 case LATCHF: 1798 showComboDialog(ON_OFF, dim); 1799 break; 1800 case SET_SENSOR: 1801 case WAIT_SENSOR: 1802 showComboDialog(SENSOR_STATES, dim); 1803 break; 1804 default: 1805 // includes cases SPEED: and RUN_WARRANT: 1806 // SPEEDSTEP and NOOP not included in ComboBox 1807 showTextDialog(dim); 1808 break; 1809 } 1810 } 1811 return editorComponent; 1812 } 1813 1814 void showTextDialog(Dimension dim) { 1815 log.debug("valueCellEditor.showTextDialog"); 1816 textDialog = new TextDialog(); 1817 textDialog._textField.setText(currentText); 1818 1819 class CellMaker implements Runnable { 1820 Dimension dim; 1821 1822 CellMaker(Dimension d) { 1823 dim = d; 1824 } 1825 1826 @Override 1827 public void run() { 1828 log.debug("Run valueCellEditor.TextDialog"); 1829 Point p = editorComponent.getLocationOnScreen(); 1830 textDialog.setLocation(p.x, p.y); 1831 textDialog.setPreferredSize(dim); 1832 textDialog.pack(); 1833 textDialog.setVisible(true); 1834 } 1835 } 1836 CellMaker t = new CellMaker(dim); 1837 javax.swing.SwingUtilities.invokeLater(t); 1838 } 1839 1840 class TextDialog extends JDialog implements FocusListener { 1841 JTextField _textField; 1842 TextDialog _this; 1843 1844 TextDialog() { 1845 super((JFrame) null, false); 1846 _this = this; 1847 _textField = new JTextField(); 1848 _textField.addFocusListener(TextDialog.this); 1849 _textField.setForeground(Color.RED); 1850 getContentPane().add(_textField); 1851 setUndecorated(true); 1852 } 1853 1854 @Override 1855 public void focusGained(FocusEvent e) { 1856 } 1857 1858 @Override 1859 public void focusLost(FocusEvent e) { 1860 currentText = _textField.getText(); 1861 ((JTextField)editorComponent).setText(currentText); 1862 fireEditingStopped(); 1863 _this.dispose(); 1864 } 1865 } 1866 1867 void showComboDialog(String[] items, Dimension dim) { 1868 editorDialog = new ComboDialog(items); 1869 log.debug("valueCellEditor.showComboDialog"); 1870 1871 class CellMaker implements Runnable { 1872 Dimension dim; 1873 1874 CellMaker(Dimension d) { 1875 dim = d; 1876 } 1877 1878 @Override 1879 public void run() { 1880 log.debug("Run valueCellEditor.showDialog"); 1881 Point p = editorComponent.getLocationOnScreen(); 1882 editorDialog.setLocation(p.x, p.y); 1883 editorDialog.setPreferredSize(dim); 1884 editorDialog.pack(); 1885 editorDialog.setVisible(true); 1886 } 1887 } 1888 CellMaker t = new CellMaker(dim); 1889 javax.swing.SwingUtilities.invokeLater(t); 1890 } 1891 1892 class ComboDialog extends JDialog implements ItemListener, FocusListener { 1893 JComboBox<String> _comboBox; 1894 ComboDialog _this; 1895 1896 ComboDialog(String[] items) { 1897 super((JFrame) null, false); 1898 _this = this; 1899 _comboBox = new JComboBox<>(); 1900 _comboBox.addItemListener(ComboDialog.this); 1901 _comboBox.addFocusListener(ComboDialog.this); 1902 _comboBox.setForeground(Color.RED); 1903 for (String item : items) { 1904 _comboBox.addItem(item); 1905 } 1906 _comboBox.removeItem(Command.NOOP.toString()); 1907 getContentPane().add(_comboBox); 1908 setUndecorated(true); 1909 } 1910 1911 @Override 1912 public void itemStateChanged(ItemEvent e) { 1913 currentText = (String) _comboBox.getSelectedItem(); 1914 ((JTextField)editorComponent).setText(currentText); 1915 fireEditingStopped(); 1916 _this.dispose(); 1917 } 1918 1919 @Override 1920 public void focusGained(FocusEvent e) { 1921 } 1922 1923 @Override 1924 public void focusLost(FocusEvent e) { 1925 currentText = (String) _comboBox.getSelectedItem(); 1926 ((JTextField)editorComponent).setText(currentText); 1927 fireEditingStopped(); 1928 _this.dispose(); 1929 } 1930 } 1931 } 1932 1933 // =============== COMMAND_COLUMN editing/rendering ===============\\ 1934 1935 private class CommandCellEditor extends DefaultCellEditor { 1936 CommandCellEditor(JComboBox<Command> comboBox) { 1937 super(comboBox); 1938 log.debug("New JComboBox<String> CommandCellEditor"); 1939 } 1940 1941 @SuppressWarnings("unchecked") // getComponent call requires an 1942 // unchecked cast 1943 @Override 1944 public Component getTableCellEditorComponent(JTable table, Object value, 1945 boolean isSelected, int row, int column) { 1946 log.debug("getTableCellEditorComponent: row= {}, column= {} selected = {}", 1947 row, column, isSelected); 1948 1949 JComboBox<Command> comboBox = (JComboBox<Command>) getComponent(); 1950 cellPt = MouseInfo.getPointerInfo().getLocation(); 1951 comboBox.removeAllItems(); 1952 for (Command cmd : Command.values()) { 1953 if (!cmd.name().equals("NOOP") && !cmd.name().equals("SPEEDSTEP")) { 1954 comboBox.addItem(cmd); 1955 } 1956 } 1957 return super.getTableCellEditorComponent(table, value, isSelected, row, column); 1958 } 1959 } 1960 1961 private Point cellPt; // point to display key 1962 1963 private class CommandCellRenderer extends DefaultTableCellRenderer { 1964 public CommandCellRenderer() { 1965 super(); 1966 log.debug("New JComboBox<String> CommandCellRenderer"); 1967 } 1968 1969 @Override 1970 public Component getTableCellRendererComponent(JTable table, Object value, 1971 boolean isSelected, boolean hasFocus, int row, int column) { 1972 Command cmd = (Command) value; 1973 int key = _throttleCommands.get(row).getKeyNum(); 1974 if (null == cmd) { 1975 setText(null); 1976 } else switch (cmd) { 1977 case FKEY: 1978 setText(Bundle.getMessage("FKey", key)); 1979 break; 1980 case LATCHF: 1981 setText(Bundle.getMessage("FKeyMomemtary", key)); 1982 break; 1983 default: 1984 setText(cmd.toString()); 1985 break; 1986 } 1987 return this; 1988 } 1989 } 1990 1991 private static class EditDialog extends JDialog { 1992 SpinnerNumberModel _keyNumModel; 1993 ThrottleSetting _ts; 1994 Command _cmd; 1995 1996 EditDialog(JFrame frame, ThrottleSetting ts, Command cmd) { 1997 super(frame, true); 1998 _ts = ts; 1999 _cmd = cmd; 2000 int key = ts.getKeyNum(); 2001 if (key < 0) { 2002 key = 0; 2003 } 2004 _keyNumModel = new SpinnerNumberModel(key, 0, 28, 1); 2005 JSpinner keyNums = new JSpinner(_keyNumModel); 2006 JPanel panel = new JPanel(); 2007 panel.setLayout(new BorderLayout()); 2008 panel.add(new JLabel(Bundle.getMessage("editFunctionKey")), BorderLayout.NORTH); 2009 panel.add(keyNums, BorderLayout.CENTER); 2010 2011 JPanel p = new JPanel(); 2012 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 2013 JButton doneButton; 2014 doneButton = new JButton(Bundle.getMessage("ButtonDone")); 2015 doneButton.addActionListener((ActionEvent a) -> done()); 2016 p.add(doneButton); 2017 2018 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 2019 cancelButton.addActionListener((ActionEvent a) -> this.dispose()); 2020 p.add(cancelButton); 2021 panel.add(p, BorderLayout.SOUTH); 2022 getContentPane().add(panel); 2023 setUndecorated(true); 2024 } 2025 2026 public void done() { 2027 int i = (Integer) _keyNumModel.getValue(); 2028 _ts.setKeyNum(i); 2029 _ts.setCommand(_cmd); 2030 this.dispose(); 2031 } 2032 2033 } 2034 2035 void makeEditWindow(ThrottleSetting ts, Command cmd) { 2036 JDialog dialog = new EditDialog(this, ts, cmd); 2037 dialog.setLocation(cellPt); 2038 dialog.pack(); 2039 dialog.setVisible(true); 2040 log.debug("makeEditWindow: pt at ({}, {})", cellPt.x, cellPt.y); 2041 } 2042 2043 private static java.text.DecimalFormat twoDigit = new java.text.DecimalFormat("0.00"); 2044 2045 /************************* Throttle Table ******************************/ 2046 private class ThrottleTableModel extends AbstractTableModel { 2047 2048 public static final int ROW_NUM = 0; 2049 public static final int TIME_COLUMN = 1; 2050 public static final int COMMAND_COLUMN = 2; 2051 public static final int VALUE_COLUMN = 3; 2052 public static final int BLOCK_COLUMN = 4; 2053 public static final int SPEED_COLUMN = 5; 2054 public static final int NUMCOLS = 6; 2055 2056 JComboBox<Integer> keyNums = new JComboBox<>(); 2057 2058 ThrottleTableModel() { 2059 super(); 2060 for (int i = 0; i < 29; i++) { 2061 keyNums.addItem(i); 2062 } 2063 } 2064 2065 @Override 2066 public int getColumnCount() { 2067 return NUMCOLS; 2068 } 2069 2070 @Override 2071 public int getRowCount() { 2072 return _throttleCommands.size(); 2073 } 2074 2075 @Override 2076 public String getColumnName(int col) { 2077 switch (col) { 2078 case ROW_NUM: 2079 return "#"; 2080 case TIME_COLUMN: 2081 return Bundle.getMessage("TimeCol"); 2082 case COMMAND_COLUMN: 2083 return Bundle.getMessage("CommandCol"); 2084 case VALUE_COLUMN: 2085 return Bundle.getMessage("ValueCol"); 2086 case BLOCK_COLUMN: 2087 return Bundle.getMessage("BlockCol"); 2088 case SPEED_COLUMN: 2089 return Bundle.getMessage("trackSpeed"); 2090 default: 2091 // fall through 2092 break; 2093 } 2094 return ""; 2095 } 2096 2097 @Override 2098 public boolean isCellEditable(int row, int col) { 2099 return !(col == ROW_NUM || col == SPEED_COLUMN); 2100 } 2101 2102 @Override 2103 public Class<?> getColumnClass(int col) { 2104 if (col == COMMAND_COLUMN) { 2105 return JComboBox.class; 2106 } 2107 return String.class; 2108 } 2109 2110 public int getPreferredWidth(int col) { 2111 switch (col) { 2112 case ROW_NUM: 2113 return new JTextField(3).getPreferredSize().width; 2114 case TIME_COLUMN: 2115 return new JTextField(8).getPreferredSize().width; 2116 case COMMAND_COLUMN: 2117 case VALUE_COLUMN: 2118 return new JTextField(18).getPreferredSize().width; 2119 case BLOCK_COLUMN: 2120 return new JTextField(45).getPreferredSize().width; 2121 case SPEED_COLUMN: 2122 return new JTextField(10).getPreferredSize().width; 2123 default: 2124 return new JTextField(12).getPreferredSize().width; 2125 } 2126 } 2127 2128 @Override 2129 public Object getValueAt(int row, int col) { 2130 // some error checking 2131 if (row >= _throttleCommands.size()) { 2132 log.debug("row {} is greater than throttle command size {}", 2133 row, _throttleCommands.size()); 2134 return ""; 2135 } 2136 ThrottleSetting ts = _throttleCommands.get(row); 2137 if (ts == null) { 2138 log.debug("Throttle setting is null!"); 2139 return ""; 2140 } 2141 switch (col) { 2142 case ROW_NUM: 2143 return row + 1; 2144 case TIME_COLUMN: 2145 return ts.getTime(); 2146 case COMMAND_COLUMN: 2147 return ts.getCommand(); 2148 case VALUE_COLUMN: 2149 CommandValue cmdVal = ts.getValue(); 2150 if (cmdVal == null) { 2151 return ""; 2152 } 2153 return cmdVal.showValue(); 2154 case BLOCK_COLUMN: 2155 return ts.getBeanDisplayName(); 2156 case SPEED_COLUMN: 2157 return twoDigit.format(ts.getTrackSpeed() * _speedConversion); 2158 default: 2159 return ""; 2160 } 2161 } 2162 2163 @Override 2164 @SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES", 2165 justification = "put least likely cases last for efficiency") 2166 public void setValueAt(Object value, int row, int col) { 2167 if (row >= _throttleCommands.size()) { 2168 return; 2169 } 2170 ThrottleSetting ts = _throttleCommands.get(row); 2171 String msg = null; 2172 switch (col) { 2173 case TIME_COLUMN: 2174 try { 2175 long time = Long.parseLong((String) value); 2176 if (time < 0) { 2177 msg = Bundle.getMessage("InvalidTime", (String) value); 2178 } else { 2179 ts.setTime(time); 2180 _dirty = true; 2181 } 2182 } catch (NumberFormatException nfe) { 2183 msg = Bundle.getMessage("InvalidTime", (String) value); 2184 } 2185 break; 2186 case COMMAND_COLUMN: 2187 Command cmd = ((Command) value); 2188 if (cmd == null) { 2189 break; 2190 } 2191 Command prCmd = ts.getCommand(); 2192 if (prCmd != null) { 2193 if (prCmd.equals(Command.NOOP)) { 2194 break; 2195 } 2196 if (!cmd.hasBlockName() && prCmd.hasBlockName()) { 2197 ts.setNamedBeanHandle(null); 2198 } 2199 } 2200 switch (cmd) { 2201 case FKEY: 2202 case LATCHF: 2203 class CellMaker implements Runnable { 2204 ThrottleSetting ts; 2205 Command cmd; 2206 2207 CellMaker(ThrottleSetting t, Command c) { 2208 ts = t; 2209 cmd = c; 2210 } 2211 2212 @Override 2213 public void run() { 2214 makeEditWindow(ts, cmd); 2215 } 2216 } 2217 CellMaker t = new CellMaker(ts, cmd); 2218 javax.swing.SwingUtilities.invokeLater(t); 2219 break; 2220 case NOOP: 2221 msg = Bundle.getMessage("cannotEnterNoop", cmd.toString()); 2222 break; 2223 case SPEED: 2224 case FORWARD: 2225 case SET_SENSOR: 2226 case WAIT_SENSOR: 2227 case RUN_WARRANT: 2228 case SPEEDSTEP: 2229 case SET_MEMORY: 2230 ts.setCommand(cmd); 2231 _dirty = true; 2232 break; 2233 default: 2234 msg = Bundle.getMessage("badCommand", cmd.toString()); 2235 } 2236 break; 2237 case VALUE_COLUMN: 2238 if (value == null || ((String) value).length() == 0) { 2239 break; 2240 } 2241 if (ts == null || ts.getCommand() == null) { 2242 msg = Bundle.getMessage("nullValue", Bundle.getMessage("CommandCol")); 2243 break; 2244 } 2245 Command command = ts.getCommand(); 2246 if (command.equals(Command.NOOP)) { 2247 break; 2248 } 2249 try { 2250 CommandValue val = ThrottleSetting.getValueFromString(command, (String) value); 2251 if (!val.equals(ts.getValue())) { 2252 _dirty = true; 2253 ts.setValue(val); 2254 } 2255 } catch (jmri.JmriException je) { 2256 msg = je.getMessage(); 2257 break; 2258 } 2259 if (command.hasBlockName()) { 2260 NamedBeanHandle<?> bh = getPreviousBlockHandle(row); 2261 ts.setNamedBeanHandle(bh); 2262 } 2263 break; 2264 case BLOCK_COLUMN: 2265 if (ts == null || ts.getCommand() == null) { 2266 msg = Bundle.getMessage("nullValue", Bundle.getMessage("CommandCol")); 2267 break; 2268 } 2269 command = ts.getCommand(); 2270 if (command == null) { 2271 break; 2272 } 2273 if (!command.hasBlockName()) { 2274 msg = ts.setNamedBean(command, (String) value); 2275 } else if (command.equals(Command.NOOP)) { 2276 if (!((String) value).equals(ts.getBeanDisplayName())) { 2277 msg = Bundle.getMessage("cannotChangeBlock", (String) value); 2278 } 2279 } else { 2280 NamedBeanHandle<?> bh = getPreviousBlockHandle(row); 2281 if (bh != null) { 2282 String name = bh.getBean().getDisplayName(); 2283 if (!name.equals(value)) { 2284 msg = Bundle.getMessage("commandInBlock", name); 2285 ts.setNamedBeanHandle(bh); 2286 _dirty = true; 2287 } 2288 } 2289 } 2290 break; 2291 case SPEED_COLUMN: 2292 break; 2293 default: 2294 } 2295 if (msg != null) { 2296 showWarning(msg); 2297 } else { 2298 fireTableRowsUpdated(row, row); 2299 } 2300 } 2301 2302 private NamedBeanHandle<? extends NamedBean> getPreviousBlockHandle(int row) { 2303 for (int i = row; i > 0; i--) { 2304 NamedBeanHandle<? extends NamedBean> bh = _throttleCommands.get(i - 1).getNamedBeanHandle(); 2305 if (bh != null && (bh.getBean() instanceof OBlock)) { 2306 return bh; 2307 } 2308 } 2309 return null; 2310 } 2311 2312 } 2313 2314 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WarrantFrame.class); 2315 2316}