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