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 default: 1109 return Bundle.getMessage("BadThrottleSetting", i + 1); 1110 } 1111 } 1112 if (lastSpeed > 0.0f) { 1113 return Bundle.getMessage("BadLastSpeed", lastSpeed); 1114 } 1115 return null; 1116 } 1117 1118 static String checkBeanName(Command command, String beanName) { 1119 switch (command) { 1120 case SET_SENSOR: 1121 case WAIT_SENSOR: 1122 if (InstanceManager.sensorManagerInstance().getSensor(beanName) == null) { 1123 return Bundle.getMessage("BadSensor", beanName); 1124 } 1125 break; 1126 case RUN_WARRANT: 1127 if (InstanceManager.getDefault(WarrantManager.class).getWarrant(beanName) == null) { 1128 return Bundle.getMessage("BadWarrant", beanName); 1129 } 1130 break; 1131 default: 1132 if (InstanceManager.getDefault(OBlockManager.class).getOBlock(beanName) == null) { 1133 return Bundle.getMessage("BlockNotFound", beanName); 1134 } 1135 break; 1136 } 1137 return null; 1138 } 1139 1140 private void runLearnModeTrain() { 1141 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1142 String msg = null; 1143 if (isRunning()) { 1144 msg = Bundle.getMessage("CannotRun", _warrant.getDisplayName(), 1145 Bundle.getMessage("TrainRunning", _warrant.getTrainName())); 1146 } 1147 if (msg == null) { 1148 _warrant.setBlockOrders(getOrders()); 1149 msg = checkTrainId(); 1150 } 1151 if (msg == null) { 1152 msg = _warrant.checkRoute(); 1153 } 1154 if (msg == null) { 1155 msg = WarrantTableFrame.getDefault().getModel().checkAddressInUse(_warrant); 1156 } 1157 if (msg == null) { 1158 msg = _warrant.allocateRoute(false, getOrders()); 1159 } 1160 toFront(); 1161 1162 if (msg != null) { 1163 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LearnError", msg), 1164 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1165 _warrant.deAllocate(); 1166 setStatus(msg, Color.red); 1167 return; 1168 } 1169 1170 if (!_throttleCommands.isEmpty()) { 1171 if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("deleteCommand"), 1172 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 1173 JmriJOptionPane.QUESTION_MESSAGE) != JmriJOptionPane.YES_OPTION ) { 1174 return; 1175 } 1176 _throttleCommands = new ArrayList<>(); 1177 _commandModel.fireTableDataChanged(); 1178 } 1179 1180 msg = _warrant.checkStartBlock(); 1181 if (msg != null) { 1182 if (msg.equals("warnStart")) { 1183 msg = Bundle.getMessage("warnStart", getTrainName(), _warrant.getCurrentBlockName()); 1184 JmriJOptionPane.showMessageDialog(this, msg, 1185 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1186 setStatus(msg, Color.red); 1187 return; 1188 } else if (msg.equals("BlockDark")) { 1189 msg = Bundle.getMessage("BlockDark", _warrant.getCurrentBlockName(), getTrainName()); 1190 if (JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog(this, 1191 Bundle.getMessage("OkToRun", msg), Bundle.getMessage("QuestionTitle"), 1192 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.WARNING_MESSAGE)) { 1193 stopRunTrain(true); 1194 setStatus(msg, Color.red); 1195 return; 1196 } 1197 } 1198 setStatus(msg, Color.black); 1199 } 1200 1201 if (_learnThrottle == null) { 1202 _learnThrottle = new LearnThrottleFrame(this); 1203 } else { 1204 _learnThrottle.setVisible(true); 1205 } 1206 1207 _warrant.setTrainName(getTrainName()); 1208 _startTime = System.currentTimeMillis(); 1209 _speed = 0.0f; 1210 1211 _warrant.addPropertyChangeListener(this); 1212 1213 msg = _warrant.setRunMode(Warrant.MODE_LEARN, _speedUtil.getDccAddress(), _learnThrottle, 1214 _throttleCommands, _runETOnlyBox.isSelected()); 1215 if (msg != null) { 1216 stopRunTrain(true); 1217 JmriJOptionPane.showMessageDialog(this, msg, Bundle.getMessage("WarningTitle"), 1218 JmriJOptionPane.WARNING_MESSAGE); 1219 setStatus(msg, Color.red); 1220 } 1221 } 1222 1223 long lastClicktime; // keep double clicks from showing dialogs 1224 protected void runTrain() { 1225 long time = System.currentTimeMillis(); 1226 if (time - lastClicktime < 1000) { 1227 return; 1228 } 1229 lastClicktime = time; 1230 1231 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1232 String msg = null; 1233 if (isRunning()) { 1234 msg = Bundle.getMessage("CannotRun", _warrant.getDisplayName(), 1235 Bundle.getMessage("TrainRunning", _warrant.getTrainName())); 1236 } 1237 if (msg == null) { 1238 _warrant.setTrainName(getTrainName()); 1239 _warrant.setShareRoute(_shareRouteBox.isSelected()); 1240 _warrant.setAddTracker(_addTracker.isSelected()); 1241 _warrant.setHaltStart(_haltStartBox.isSelected()); 1242 _warrant.setNoRamp(_noRampBox.isSelected()); 1243 } 1244 if (msg == null) { 1245 msg = checkTrainId(); 1246 } 1247 if (msg == null) { 1248 msg = checkThrottleCommands(); 1249 if (msg == null) { 1250 if (!_warrant.hasRouteSet() && _runETOnlyBox.isSelected()) { 1251 msg = Bundle.getMessage("BlindRouteNotSet", _warrant.getDisplayName()); 1252 } 1253 } 1254 } 1255 if (msg == null) { 1256 WarrantTableModel model = WarrantTableFrame.getDefault().getModel(); 1257 msg = model.checkAddressInUse(_warrant); 1258 } 1259// toFront(); 1260 if (msg != null) { 1261 JmriJOptionPane.showMessageDialog(this, msg, Bundle.getMessage("WarningTitle"), 1262 JmriJOptionPane.WARNING_MESSAGE); 1263// _warrant.deAllocate(); 1264 setStatus(msg, Color.black); 1265 return; 1266 } 1267 if (_warrant.getRunMode() != Warrant.MODE_NONE) { 1268 return; 1269 } 1270 _warrant.addPropertyChangeListener(this); 1271 1272 msg = _warrant.setRunMode(Warrant.MODE_RUN, _speedUtil.getDccAddress(), null, 1273 _throttleCommands, _runETOnlyBox.isSelected()); 1274 if (msg != null) { 1275 clearWarrant(); 1276 JmriJOptionPane.showMessageDialog(this, msg, 1277 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1278 setStatus(msg, Color.red); 1279 return; 1280 } 1281 1282 msg = _warrant.checkStartBlock(); 1283 if (msg != null) { 1284 if (msg.equals("warnStart")) { 1285 msg = Bundle.getMessage("warnStart", _warrant.getTrainName(), _warrant.getCurrentBlockName()); 1286 } else if (msg.equals("BlockDark")) { 1287 msg = Bundle.getMessage("BlockDark", _warrant.getCurrentBlockName(), _warrant.getTrainName()); 1288 } 1289 if (JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog(this, 1290 Bundle.getMessage("OkToRun", msg), Bundle.getMessage("QuestionTitle"), 1291 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.WARNING_MESSAGE)) { 1292 clearWarrant(); 1293 setStatus(msg, Color.red); 1294 } else { 1295 setStatus(_warrant.getRunningMessage(), myGreen); 1296 } 1297 } 1298 } 1299 1300 /* 1301 * Stop a MODE_LEARN warrant, i.e. non-registered member _warrant 1302 */ 1303 private void stopRunTrain(boolean aborted) { 1304 if (_learnThrottle != null) { 1305 _learnThrottle.dispose(); 1306 _learnThrottle = null; 1307 } 1308 if (_warrant == null) { 1309 return; 1310 } 1311 1312 if (_warrant.getRunMode() == Warrant.MODE_LEARN) { 1313 List<BlockOrder> orders = getOrders(); 1314 if (orders != null && orders.size() > 1) { 1315 BlockOrder bo = _warrant.getCurrentBlockOrder(); 1316 if (bo != null) { 1317 OBlock lastBlock = orders.get(orders.size() - 1).getBlock(); 1318 OBlock currentBlock = bo.getBlock(); 1319 if (!lastBlock.equals(currentBlock)) { 1320 if ((lastBlock.getState() & OBlock.UNDETECTED) != 0 && 1321 currentBlock.equals(orders.get(orders.size() - 2).getBlock())) { 1322 setThrottleCommand("NoOp", Bundle.getMessage("Mark"), lastBlock.getDisplayName()); 1323 setStatus(Bundle.getMessage("LearningStop"), myGreen); 1324 } else if (!aborted) { 1325 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("IncompleteScript", lastBlock), 1326 Bundle.getMessage("WarningTitle"), 1327 JmriJOptionPane.WARNING_MESSAGE); 1328 } 1329 } else { 1330 setStatus(Bundle.getMessage("LearningStop"), myGreen); 1331 } 1332 } 1333 } 1334 } 1335 clearWarrant(); 1336 } 1337 1338 private void clearWarrant() { 1339 if (_warrant != null) { 1340 _warrant.stopWarrant(false, true); 1341 _warrant.removePropertyChangeListener(this); 1342 } 1343 } 1344 1345 protected Warrant getWarrant() { 1346 return _warrant; 1347 } 1348 1349 private void setStatus(String msg, Color c) { 1350 ThreadingUtil.runOnGUIEventually(() -> { 1351 _statusBox.setForeground(c); 1352 _statusBox.setText(msg); 1353 }); 1354 } 1355 1356 @Override 1357 protected void maxThrottleEventAction() { 1358 } 1359 1360 /** 1361 * Property names from Warrant: "runMode" - from setRunMode "controlChange" 1362 * - from controlRunTrain "blockChange" - from goingActive "allocate" - from 1363 * allocateRoute, deAllocate "setRoute" - from setRoute, goingActive 1364 * Property names from Engineer: "Command" - from run "SpeedRestriction" - 1365 * ThrottleRamp run Property names from RouteFinder: "RouteSearch" - from 1366 * run 1367 */ 1368 @Override 1369 public void propertyChange(java.beans.PropertyChangeEvent e) { 1370 String property = e.getPropertyName(); 1371 if (property.equals("DnDrop")) { 1372 doAction(e.getSource()); 1373 } else if (e.getSource() instanceof Warrant && _warrant.equals(e.getSource())) { 1374 if (log.isDebugEnabled()) 1375 log.debug("propertyChange \"{}\" old= {} new= {} source= {}", 1376 property, e.getOldValue(), e.getNewValue(), e.getSource().getClass().getName()); 1377 String msg = null; 1378 Color color = myGreen; 1379 switch (_warrant.getRunMode()) { 1380 case Warrant.MODE_NONE: 1381 _warrant.removePropertyChangeListener(this); 1382 if (property.equals("StopWarrant")) { 1383 String blkName = (String) e.getOldValue(); 1384 String bundleKey = (String) e.getNewValue(); 1385 if (blkName == null) { 1386 msg = Bundle.getMessage(bundleKey, 1387 _warrant.getTrainName(), _warrant.getDisplayName()); 1388 color = Color.red; 1389 } else { 1390 msg = Bundle.getMessage(bundleKey, 1391 _warrant.getTrainName(), _warrant.getDisplayName(), 1392 blkName); 1393 color = myGreen; 1394 } 1395 } 1396 break; 1397 case Warrant.MODE_LEARN: 1398 if (property.equals("blockChange")) { 1399 OBlock oldBlock = (OBlock) e.getOldValue(); 1400 OBlock newBlock = (OBlock) e.getNewValue(); 1401 if (newBlock == null) { 1402 stopRunTrain(true); 1403 msg = Bundle.getMessage("ChangedRoute", 1404 _warrant.getTrainName(), 1405 oldBlock.getDisplayName(), 1406 _warrant.getDisplayName()); 1407 color = Color.red; 1408 } else { 1409 setThrottleCommand("NoOp", Bundle.getMessage("Mark"), 1410 ((OBlock) e.getNewValue()).getDisplayName()); 1411 msg = Bundle.getMessage("TrackerBlockEnter", 1412 _warrant.getTrainName(), 1413 newBlock.getDisplayName()); 1414 } 1415 } else if (property.equals("abortLearn")) { 1416 stopRunTrain(true); 1417 int oldIdx = ((Integer) e.getOldValue()); 1418 int newIdx = ((Integer) e.getNewValue()); 1419 if (oldIdx > newIdx) { 1420 msg = Bundle.getMessage("LearnAbortOccupied", 1421 _warrant.getBlockAt(oldIdx), 1422 _warrant.getDisplayName()); 1423 color = Color.red; 1424 } else { 1425 msg = Bundle.getMessage("warrantAbort", 1426 _warrant.getTrainName(), 1427 _warrant.getDisplayName()); 1428 color = Color.red; 1429 } 1430 } else { 1431 msg = Bundle.getMessage("Learning", _warrant.getCurrentBlockName()); 1432 color = Color.black; 1433 } 1434 break; 1435 case Warrant.MODE_RUN: 1436 case Warrant.MODE_MANUAL: 1437 if (e.getPropertyName().equals("blockChange")) { 1438 OBlock oldBlock = (OBlock) e.getOldValue(); 1439 OBlock newBlock = (OBlock) e.getNewValue(); 1440 if (newBlock == null) { 1441 msg = Bundle.getMessage("ChangedRoute", 1442 _warrant.getTrainName(), 1443 oldBlock.getDisplayName(), 1444 _warrant.getDisplayName()); 1445 color = Color.red; 1446 } else { 1447 msg = Bundle.getMessage("TrackerBlockEnter", 1448 _warrant.getTrainName(), 1449 newBlock.getDisplayName()); 1450 } 1451 } else if (e.getPropertyName().equals("ReadyToRun")) { 1452 msg = _warrant.getRunningMessage(); 1453 } else if (e.getPropertyName().equals("SpeedChange")) { 1454 msg = _warrant.getRunningMessage(); 1455 color = Color.black; 1456 } else if (property.equals("SignalOverrun")) { 1457 String name = (String) e.getOldValue(); 1458 String speed = (String) e.getNewValue(); 1459 msg = Bundle.getMessage("SignalOverrun", 1460 _warrant.getTrainName(), speed, name); 1461 color = Color.red; 1462 } else if (property.equals("OccupyOverrun")) { 1463 String blockName = (String) e.getOldValue(); 1464 OBlock occuppier = (OBlock) e.getNewValue(); 1465 msg = Bundle.getMessage("OccupyOverrun", 1466 _warrant.getTrainName(), blockName, occuppier); 1467 color = Color.red; 1468 } else if (property.equals("WarrantOverrun")) { 1469 String blkName = (String) e.getOldValue(); 1470 OBlock warName = (OBlock) e.getNewValue(); 1471 msg = Bundle.getMessage("WarrantOverrun", 1472 _warrant.getTrainName(), blkName, warName); 1473 color = Color.red; 1474 } else if (e.getPropertyName().equals("WarrantStart")) { 1475 msg = Bundle.getMessage("warrantStart", 1476 _warrant.getTrainName(), _warrant.getDisplayName(), 1477 _warrant.getCurrentBlockName()); 1478 if (_warrant.getState() == Warrant.HALT) { 1479 JmriJOptionPane.showMessageDialog(this, _warrant.getRunningMessage(), 1480 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1481 } 1482 } else if (e.getPropertyName().equals("controlChange")) { 1483 int newCntrl = ((Integer) e.getNewValue()); 1484 msg = Bundle.getMessage("controlChange", 1485 _warrant.getTrainName(), 1486 Bundle.getMessage(Warrant.CNTRL_CMDS[newCntrl]), 1487 _warrant.getCurrentBlockName()); 1488 color = Color.black; 1489 } else if (e.getPropertyName().equals("throttleFail")) { 1490 msg = Bundle.getMessage("ThrottleFail", 1491 _warrant.getTrainName(), e.getNewValue()); 1492 color = Color.red; 1493 } else { 1494 return; 1495 } 1496 break; 1497 default: 1498 } 1499 setStatus(msg, color); 1500 } 1501 invalidate(); 1502 } 1503 1504 protected void setThrottleCommand(String cmd, String value) { 1505 String bName = Bundle.getMessage("NoBlock"); 1506 BlockOrder bo = _warrant.getCurrentBlockOrder(); 1507 if (bo != null) { 1508 OBlock block = bo.getBlock(); 1509 if (block != null) { 1510 bName = block.getDisplayName(); 1511 } 1512 } 1513 /* 1514 * if (cmd.equals("Forward")) { 1515 * _speedUtil.setIsForward(Boolean.parseBoolean(value)); } 1516 */ 1517 setThrottleCommand(cmd, value, bName); 1518 } 1519 1520 protected void setSpeedCommand(float speed) { 1521 if (_warrant.getSpeedUtil().profileHasSpeedInfo()) { 1522 _speed = _warrant.getSpeedUtil().getTrackSpeed(speed); // mm/ms 1523 } else { 1524 _speed = 0.0f; 1525 } 1526 setThrottleCommand("speed", Float.toString(speed)); 1527 } 1528 1529 private void setThrottleCommand(String cmd, String value, String bName) { 1530 long endTime = System.currentTimeMillis(); 1531 long time = endTime - _startTime; 1532 _startTime = endTime; 1533 ThrottleSetting ts = new ThrottleSetting(time, cmd, value, bName, _speed); 1534 if (log.isDebugEnabled()) { 1535 log.debug("setThrottleCommand= {}", ts.toString()); 1536 } 1537 _throttleCommands.add(ts); 1538 _commandModel.fireTableDataChanged(); 1539 1540 scrollCommandTable(_commandModel.getRowCount()); 1541 } 1542 1543 private void scrollCommandTable(int row) { 1544 JScrollBar bar = _throttlePane.getVerticalScrollBar(); 1545 bar.setValue(row * _rowHeight); 1546 bar.invalidate(); 1547 } 1548 1549 /** 1550 * Called by WarrantTableAction before closing the editing of this warrant 1551 * 1552 * @return true if this warrant or its pre-editing version is running 1553 */ 1554 protected boolean isRunning() { 1555 return _warrant._runMode != Warrant.MODE_NONE || 1556 (_saveWarrant != null && _saveWarrant._runMode != Warrant.MODE_NONE); 1557 } 1558 1559 /** 1560 * Verify that commands are correct 1561 * 1562 * @return true if commands are OK 1563 */ 1564 private boolean save() { 1565 boolean fatal = false; 1566 String msg = null; 1567 if (isRunning()) { 1568 msg = Bundle.getMessage("CannotEdit", _warrant.getDisplayName()); 1569 } 1570 if (msg == null) { 1571 msg = routeIsValid(); 1572 } 1573 if (msg != null) { 1574 msg = Bundle.getMessage("SaveError", msg); 1575 fatal = true; 1576 } 1577 if (msg == null) { 1578 msg = checkLocoAddress(); 1579 } 1580 if (msg == null && !_isSCWarrant.isSelected()) { 1581 msg = checkThrottleCommands(); 1582 if (msg != null) { 1583 msg = Bundle.getMessage("BadData", msg); 1584 fatal = true; 1585 } 1586 } 1587 1588 WarrantManager mgr = InstanceManager.getDefault(WarrantManager.class); 1589 if (msg == null) { 1590 if (_saveWarrant != null) { 1591 if ((_saveWarrant instanceof SCWarrant && !_isSCWarrant.isSelected()) || 1592 (!(_saveWarrant instanceof SCWarrant) && _isSCWarrant.isSelected())) { 1593 // _saveWarrant already registered, but is not the correct 1594 // class. 1595 mgr.deregister(_saveWarrant); 1596 _warrant = mgr.createNewWarrant( 1597 _sysNameBox.getText(), _userNameBox.getText(), _isSCWarrant.isSelected(), 1598 (long) _TTPtextField.getValue()); 1599 } else { 1600 String uName = _userNameBox.getText(); 1601 if (uName.length() > 0 && 1602 !uName.equals(_saveWarrant.getUserName()) && 1603 mgr.getWarrant(uName) != null) { 1604 fatal = true; 1605 msg = Bundle.getMessage("WarrantExists", _userNameBox.getText()); 1606 } else { 1607 _warrant = _saveWarrant; // update registered warrant 1608 } 1609 } 1610 } else { 1611 if (_warrant == null) { 1612 _warrant = mgr.createNewWarrant( 1613 _sysNameBox.getText(), _userNameBox.getText(), 1614 _isSCWarrant.isSelected(), (long) _TTPtextField.getValue()); 1615 } 1616 } 1617 } 1618 if (_warrant == null) { // find out why 1619 if (_userNameBox.getText().length() > 0 && mgr.getByUserName(_userNameBox.getText()) != null) { 1620 msg = Bundle.getMessage("WarrantExists", _userNameBox.getText()); 1621 } else if (mgr.getBySystemName(_sysNameBox.getText()) != null) { 1622 msg = Bundle.getMessage("WarrantExists", _sysNameBox.getText()); 1623 } else { 1624 msg = Bundle.getMessage("IWSystemName", _sysNameBox.getText()); 1625 } 1626 fatal = true; 1627 } 1628 if (msg == null && _userNameBox.getText().length() == 0) { 1629 msg = Bundle.getMessage("NoUserName", _sysNameBox.getText()); 1630 } 1631 if (msg != null) { 1632 if (fatal) { 1633 JmriJOptionPane.showMessageDialog(this, msg, 1634 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1635 return false; 1636 } 1637 int result = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("SaveQuestion", msg), 1638 Bundle.getMessage("QuestionTitle"), 1639 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE); 1640 if (result != JmriJOptionPane.YES_OPTION ) { 1641 if (_warrant != null) { 1642 mgr.deregister(_warrant); 1643 } 1644 return false; 1645 } 1646 } 1647 1648 if (_isSCWarrant.isSelected()) { 1649 ((SCWarrant) _warrant).setForward(_runForward.isSelected()); 1650 ((SCWarrant) _warrant).setTimeToPlatform((long) _TTPtextField.getValue()); 1651 long sf = (long) _speedFactorTextField.getValue(); 1652 float sf_float = sf; 1653 ((SCWarrant) _warrant).setSpeedFactor(sf_float / 100); 1654 } 1655 _warrant.setTrainName(getTrainName()); 1656 _warrant.setRunBlind(_runETOnlyBox.isSelected()); 1657 _warrant.setShareRoute(_shareRouteBox.isSelected()); 1658 _warrant.setAddTracker(_addTracker.isSelected()); 1659 _warrant.setNoRamp(_noRampBox.isSelected()); 1660 _warrant.setHaltStart(_haltStartBox.isSelected()); 1661 _warrant.setUserName(_userNameBox.getText()); 1662 1663 _warrant.setViaOrder(getViaBlockOrder()); 1664 _warrant.setAvoidOrder(getAvoidBlockOrder()); 1665 _warrant.setBlockOrders(getOrders()); 1666 _warrant.setThrottleCommands(_throttleCommands); 1667 _warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 1668 if (_saveWarrant == null) { 1669 try { 1670 mgr.register(_warrant); 1671 } catch (jmri.NamedBean.DuplicateSystemNameException dsne) { 1672 // ignore 1673 } 1674 _saveWarrant = _warrant; 1675 } 1676 1677 if (log.isDebugEnabled()) 1678 log.debug("warrant {} saved _train {} name= {}", 1679 _warrant.getDisplayName(), _speedUtil.getRosterId(), getTrainName()); 1680 WarrantTableAction.getDefault().updateWarrantMenu(); 1681 WarrantTableFrame.getDefault().getModel().fireTableDataChanged(); 1682 _dirty = false; 1683 return true; 1684 } 1685 1686 protected List<ThrottleSetting> getThrottleCommands() { 1687 return _throttleCommands; 1688 } 1689 1690 protected void close() { 1691 _dirty = false; 1692 clearTempWarrant(); 1693 if (_warrant.getRunMode() != Warrant.MODE_NONE) { 1694 stopRunTrain(true); 1695 } 1696 closeProfileTable(); 1697 dispose(); 1698 } 1699 1700 // =============== Throttle Command Table ==========================\\ 1701 // =============== VALUE_COLUMN editing/rendering ==================\\ 1702 1703 static String[] TRUE_FALSE = {ValueType.VAL_TRUE.toString(), ValueType.VAL_FALSE.toString()}; 1704 static String[] ON_OFF = {ValueType.VAL_ON.toString(), ValueType.VAL_OFF.toString()}; 1705 static String[] SENSOR_STATES = {ValueType.VAL_ACTIVE.toString(), ValueType.VAL_INACTIVE.toString()}; 1706 1707 class ValueCellEditor extends DefaultCellEditor { 1708 1709 private ComboDialog editorDialog; 1710 private TextDialog textDialog; 1711 private String currentText; 1712 1713 ValueCellEditor(JTextField textField) { 1714 super(textField); 1715 setClickCountToStart(1); 1716 log.debug("valueCellEditor Ctor"); 1717 } 1718 1719 @Override 1720 public Component getTableCellEditorComponent(JTable table, Object value, 1721 boolean isSelected, int row, int col) { 1722 if (log.isDebugEnabled()) { 1723 log.debug("getValueCellEditorComponent: row= {}, column= {} selected = {} value= {}", 1724 row, col, isSelected, value); 1725 } 1726 currentText = value.toString(); 1727 editorComponent = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, col); 1728 Command cmd = (Command) _commandModel.getValueAt(row, ThrottleTableModel.COMMAND_COLUMN); 1729 Rectangle cellRect = table.getCellRect(row, col, false); 1730 Dimension dim = new Dimension(cellRect.width, cellRect.height); 1731 1732 if (cmd == null) { 1733 showTextDialog(dim); 1734 } else { 1735 switch (cmd) { 1736 case FORWARD: 1737 showComboDialog(TRUE_FALSE, dim); 1738 break; 1739 case FKEY: 1740 case LATCHF: 1741 showComboDialog(ON_OFF, dim); 1742 break; 1743 case SET_SENSOR: 1744 case WAIT_SENSOR: 1745 showComboDialog(SENSOR_STATES, dim); 1746 break; 1747 default: 1748 // includes cases SPEED: and RUN_WARRANT: 1749 // SPEEDSTEP and NOOP not included in ComboBox 1750 showTextDialog(dim); 1751 break; 1752 } 1753 } 1754 return editorComponent; 1755 } 1756 1757 void showTextDialog(Dimension dim) { 1758 log.debug("valueCellEditor.showTextDialog"); 1759 textDialog = new TextDialog(); 1760 textDialog._textField.setText(currentText); 1761 1762 class CellMaker implements Runnable { 1763 Dimension dim; 1764 1765 CellMaker(Dimension d) { 1766 dim = d; 1767 } 1768 1769 @Override 1770 public void run() { 1771 log.debug("Run valueCellEditor.TextDialog"); 1772 Point p = editorComponent.getLocationOnScreen(); 1773 textDialog.setLocation(p.x, p.y); 1774 textDialog.setPreferredSize(dim); 1775 textDialog.pack(); 1776 textDialog.setVisible(true); 1777 } 1778 } 1779 CellMaker t = new CellMaker(dim); 1780 javax.swing.SwingUtilities.invokeLater(t); 1781 } 1782 1783 class TextDialog extends JDialog implements FocusListener { 1784 JTextField _textField; 1785 TextDialog _this; 1786 1787 TextDialog() { 1788 super((JFrame) null, false); 1789 _this = this; 1790 _textField = new JTextField(); 1791 _textField.addFocusListener(TextDialog.this); 1792 _textField.setForeground(Color.RED); 1793 getContentPane().add(_textField); 1794 setUndecorated(true); 1795 } 1796 1797 @Override 1798 public void focusGained(FocusEvent e) { 1799 } 1800 1801 @Override 1802 public void focusLost(FocusEvent e) { 1803 currentText = _textField.getText(); 1804 ((JTextField)editorComponent).setText(currentText); 1805 fireEditingStopped(); 1806 _this.dispose(); 1807 } 1808 } 1809 1810 void showComboDialog(String[] items, Dimension dim) { 1811 editorDialog = new ComboDialog(items); 1812 log.debug("valueCellEditor.showComboDialog"); 1813 1814 class CellMaker implements Runnable { 1815 Dimension dim; 1816 1817 CellMaker(Dimension d) { 1818 dim = d; 1819 } 1820 1821 @Override 1822 public void run() { 1823 log.debug("Run valueCellEditor.showDialog"); 1824 Point p = editorComponent.getLocationOnScreen(); 1825 editorDialog.setLocation(p.x, p.y); 1826 editorDialog.setPreferredSize(dim); 1827 editorDialog.pack(); 1828 editorDialog.setVisible(true); 1829 } 1830 } 1831 CellMaker t = new CellMaker(dim); 1832 javax.swing.SwingUtilities.invokeLater(t); 1833 } 1834 1835 class ComboDialog extends JDialog implements ItemListener, FocusListener { 1836 JComboBox<String> _comboBox; 1837 ComboDialog _this; 1838 1839 ComboDialog(String[] items) { 1840 super((JFrame) null, false); 1841 _this = this; 1842 _comboBox = new JComboBox<>(); 1843 _comboBox.addItemListener(ComboDialog.this); 1844 _comboBox.addFocusListener(ComboDialog.this); 1845 _comboBox.setForeground(Color.RED); 1846 for (String item : items) { 1847 _comboBox.addItem(item); 1848 } 1849 _comboBox.removeItem(Command.NOOP.toString()); 1850 getContentPane().add(_comboBox); 1851 setUndecorated(true); 1852 } 1853 1854 @Override 1855 public void itemStateChanged(ItemEvent e) { 1856 currentText = (String) _comboBox.getSelectedItem(); 1857 ((JTextField)editorComponent).setText(currentText); 1858 fireEditingStopped(); 1859 _this.dispose(); 1860 } 1861 1862 @Override 1863 public void focusGained(FocusEvent e) { 1864 } 1865 1866 @Override 1867 public void focusLost(FocusEvent e) { 1868 currentText = (String) _comboBox.getSelectedItem(); 1869 ((JTextField)editorComponent).setText(currentText); 1870 fireEditingStopped(); 1871 _this.dispose(); 1872 } 1873 } 1874 } 1875 1876 // =============== COMMAND_COLUMN editing/rendering ===============\\ 1877 1878 class CommandCellEditor extends DefaultCellEditor { 1879 CommandCellEditor(JComboBox<Command> comboBox) { 1880 super(comboBox); 1881 log.debug("New JComboBox<String> CommandCellEditor"); 1882 } 1883 1884 @SuppressWarnings("unchecked") // getComponent call requires an 1885 // unchecked cast 1886 @Override 1887 public Component getTableCellEditorComponent(JTable table, Object value, 1888 boolean isSelected, int row, int column) { 1889 if (log.isDebugEnabled()) { 1890 log.debug("getTableCellEditorComponent: row= {}, column= {} selected = {}", 1891 row, column, isSelected); 1892 } 1893 JComboBox<Command> comboBox = (JComboBox<Command>) getComponent(); 1894 cellPt = MouseInfo.getPointerInfo().getLocation(); 1895 comboBox.removeAllItems(); 1896 for (Command cmd : Command.values()) { 1897 if (!cmd.name().equals("NOOP") && !cmd.name().equals("SPEEDSTEP")) { 1898 comboBox.addItem(cmd); 1899 } 1900 } 1901 return super.getTableCellEditorComponent(table, value, isSelected, row, column); 1902 } 1903 } 1904 1905 Point cellPt; // point to display key 1906 1907 class CommandCellRenderer extends DefaultTableCellRenderer { 1908 public CommandCellRenderer() { 1909 super(); 1910 log.debug("New JComboBox<String> CommandCellRenderer"); 1911 } 1912 1913 @Override 1914 public Component getTableCellRendererComponent(JTable table, Object value, 1915 boolean isSelected, boolean hasFocus, int row, int column) { 1916 Command cmd = (Command) value; 1917 int key = _throttleCommands.get(row).getKeyNum(); 1918 if (null == cmd) { 1919 setText(null); 1920 } else switch (cmd) { 1921 case FKEY: 1922 setText(Bundle.getMessage("FKey", key)); 1923 break; 1924 case LATCHF: 1925 setText(Bundle.getMessage("FKeyMomemtary", key)); 1926 break; 1927 default: 1928 setText(cmd.toString()); 1929 break; 1930 } 1931 return this; 1932 } 1933 } 1934 1935 static class EditDialog extends JDialog { 1936 SpinnerNumberModel _keyNumModel; 1937 ThrottleSetting _ts; 1938 Command _cmd; 1939 1940 EditDialog(JFrame frame, ThrottleSetting ts, Command cmd) { 1941 super(frame, true); 1942 _ts = ts; 1943 _cmd = cmd; 1944 int key = ts.getKeyNum(); 1945 if (key < 0) { 1946 key = 0; 1947 } 1948 _keyNumModel = new SpinnerNumberModel(key, 0, 28, 1); 1949 JSpinner keyNums = new JSpinner(_keyNumModel); 1950 JPanel panel = new JPanel(); 1951 panel.setLayout(new BorderLayout()); 1952 panel.add(new JLabel(Bundle.getMessage("editFunctionKey")), BorderLayout.NORTH); 1953 panel.add(keyNums, BorderLayout.CENTER); 1954 1955 JPanel p = new JPanel(); 1956 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 1957 JButton doneButton; 1958 doneButton = new JButton(Bundle.getMessage("ButtonDone")); 1959 doneButton.addActionListener((ActionEvent a) -> done()); 1960 p.add(doneButton); 1961 1962 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 1963 cancelButton.addActionListener((ActionEvent a) -> this.dispose()); 1964 p.add(cancelButton); 1965 panel.add(p, BorderLayout.SOUTH); 1966 getContentPane().add(panel); 1967 setUndecorated(true); 1968 } 1969 1970 public void done() { 1971 int i = (Integer) _keyNumModel.getValue(); 1972 _ts.setKeyNum(i); 1973 _ts.setCommand(_cmd); 1974 this.dispose(); 1975 } 1976 1977 } 1978 1979 void makeEditWindow(ThrottleSetting ts, Command cmd) { 1980 JDialog dialog = new EditDialog(this, ts, cmd); 1981 dialog.setLocation(cellPt); 1982 dialog.pack(); 1983 dialog.setVisible(true); 1984 if (log.isDebugEnabled()) { 1985 log.debug("makeEditWindow: pt at ({}, {})", cellPt.x, cellPt.y); 1986 } 1987 } 1988 1989 static java.text.DecimalFormat twoDigit = new java.text.DecimalFormat("0.00"); 1990 1991 /************************* Throttle Table ******************************/ 1992 class ThrottleTableModel extends AbstractTableModel { 1993 1994 public static final int ROW_NUM = 0; 1995 public static final int TIME_COLUMN = 1; 1996 public static final int COMMAND_COLUMN = 2; 1997 public static final int VALUE_COLUMN = 3; 1998 public static final int BLOCK_COLUMN = 4; 1999 public static final int SPEED_COLUMN = 5; 2000 public static final int NUMCOLS = 6; 2001 2002 JComboBox<Integer> keyNums = new JComboBox<>(); 2003 2004 public ThrottleTableModel() { 2005 super(); 2006 for (int i = 0; i < 29; i++) { 2007 keyNums.addItem(i); 2008 } 2009 } 2010 2011 @Override 2012 public int getColumnCount() { 2013 return NUMCOLS; 2014 } 2015 2016 @Override 2017 public int getRowCount() { 2018 return _throttleCommands.size(); 2019 } 2020 2021 @Override 2022 public String getColumnName(int col) { 2023 switch (col) { 2024 case ROW_NUM: 2025 return "#"; 2026 case TIME_COLUMN: 2027 return Bundle.getMessage("TimeCol"); 2028 case COMMAND_COLUMN: 2029 return Bundle.getMessage("CommandCol"); 2030 case VALUE_COLUMN: 2031 return Bundle.getMessage("ValueCol"); 2032 case BLOCK_COLUMN: 2033 return Bundle.getMessage("BlockCol"); 2034 case SPEED_COLUMN: 2035 return Bundle.getMessage("trackSpeed"); 2036 default: 2037 // fall through 2038 break; 2039 } 2040 return ""; 2041 } 2042 2043 @Override 2044 public boolean isCellEditable(int row, int col) { 2045 return !(col == ROW_NUM || col == SPEED_COLUMN); 2046 } 2047 2048 @Override 2049 public Class<?> getColumnClass(int col) { 2050 if (col == COMMAND_COLUMN) { 2051 return JComboBox.class; 2052 } 2053 return String.class; 2054 } 2055 2056 public int getPreferredWidth(int col) { 2057 switch (col) { 2058 case ROW_NUM: 2059 return new JTextField(3).getPreferredSize().width; 2060 case TIME_COLUMN: 2061 return new JTextField(8).getPreferredSize().width; 2062 case COMMAND_COLUMN: 2063 case VALUE_COLUMN: 2064 return new JTextField(18).getPreferredSize().width; 2065 case BLOCK_COLUMN: 2066 return new JTextField(45).getPreferredSize().width; 2067 case SPEED_COLUMN: 2068 return new JTextField(10).getPreferredSize().width; 2069 default: 2070 return new JTextField(12).getPreferredSize().width; 2071 } 2072 } 2073 2074 @Override 2075 public Object getValueAt(int row, int col) { 2076 // some error checking 2077 if (row >= _throttleCommands.size()) { 2078 if (log.isDebugEnabled()) 2079 log.debug("row {} is greater than throttle command size {}", 2080 row, _throttleCommands.size()); 2081 return ""; 2082 } 2083 ThrottleSetting ts = _throttleCommands.get(row); 2084 if (ts == null) { 2085 if (log.isDebugEnabled()) 2086 log.debug("Throttle setting is null!"); 2087 return ""; 2088 } 2089 switch (col) { 2090 case ROW_NUM: 2091 return row + 1; 2092 case TIME_COLUMN: 2093 return ts.getTime(); 2094 case COMMAND_COLUMN: 2095 return ts.getCommand(); 2096 case VALUE_COLUMN: 2097 CommandValue cmdVal = ts.getValue(); 2098 if (cmdVal == null) { 2099 return ""; 2100 } 2101 return cmdVal.showValue(); 2102 case BLOCK_COLUMN: 2103 return ts.getBeanDisplayName(); 2104 case SPEED_COLUMN: 2105 return twoDigit.format(ts.getTrackSpeed() * _speedConversion); 2106 default: 2107 return ""; 2108 } 2109 } 2110 2111 @Override 2112 @SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES", 2113 justification = "put least likely cases last for efficiency") 2114 public void setValueAt(Object value, int row, int col) { 2115 if (row >= _throttleCommands.size()) { 2116 return; 2117 } 2118 ThrottleSetting ts = _throttleCommands.get(row); 2119 String msg = null; 2120 switch (col) { 2121 case TIME_COLUMN: 2122 try { 2123 long time = Long.parseLong((String) value); 2124 if (time < 0) { 2125 msg = Bundle.getMessage("InvalidTime", (String) value); 2126 } else { 2127 ts.setTime(time); 2128 _dirty = true; 2129 } 2130 } catch (NumberFormatException nfe) { 2131 msg = Bundle.getMessage("InvalidTime", (String) value); 2132 } 2133 break; 2134 case COMMAND_COLUMN: 2135 Command cmd = ((Command) value); 2136 if (cmd == null) { 2137 break; 2138 } 2139 Command prCmd = ts.getCommand(); 2140 if (prCmd != null) { 2141 if (prCmd.equals(Command.NOOP)) { 2142 break; 2143 } 2144 if (!cmd.hasBlockName() && prCmd.hasBlockName()) { 2145 ts.setNamedBeanHandle(null); 2146 } 2147 } 2148 switch (cmd) { 2149 case FKEY: 2150 case LATCHF: 2151 class CellMaker implements Runnable { 2152 ThrottleSetting ts; 2153 Command cmd; 2154 2155 CellMaker(ThrottleSetting t, Command c) { 2156 ts = t; 2157 cmd = c; 2158 } 2159 2160 @Override 2161 public void run() { 2162 makeEditWindow(ts, cmd); 2163 } 2164 } 2165 CellMaker t = new CellMaker(ts, cmd); 2166 javax.swing.SwingUtilities.invokeLater(t); 2167 break; 2168 case NOOP: 2169 msg = Bundle.getMessage("cannotEnterNoop", cmd.toString()); 2170 break; 2171 case SPEED: 2172 case FORWARD: 2173 case SET_SENSOR: 2174 case WAIT_SENSOR: 2175 case RUN_WARRANT: 2176 case SPEEDSTEP: 2177 ts.setCommand(cmd); 2178 _dirty = true; 2179 break; 2180 default: 2181 msg = Bundle.getMessage("badCommand", cmd.toString()); 2182 } 2183 break; 2184 case VALUE_COLUMN: 2185 if (value == null || ((String) value).length() == 0) { 2186 break; 2187 } 2188 if (ts == null || ts.getCommand() == null) { 2189 msg = Bundle.getMessage("nullValue", Bundle.getMessage("CommandCol")); 2190 break; 2191 } 2192 Command command = ts.getCommand(); 2193 if (command.equals(Command.NOOP)) { 2194 break; 2195 } 2196 try { 2197 CommandValue val = ThrottleSetting.getValueFromString(command, (String) value); 2198 if (!val.equals(ts.getValue())) { 2199 _dirty = true; 2200 ts.setValue(val); 2201 } 2202 } catch (jmri.JmriException je) { 2203 msg = je.getMessage(); 2204 break; 2205 } 2206 if (command.hasBlockName()) { 2207 NamedBeanHandle<?> bh = getPreviousBlockHandle(row); 2208 ts.setNamedBeanHandle(bh); 2209 } 2210 break; 2211 case BLOCK_COLUMN: 2212 if (ts == null || ts.getCommand() == null) { 2213 msg = Bundle.getMessage("nullValue", Bundle.getMessage("CommandCol")); 2214 break; 2215 } 2216 command = ts.getCommand(); 2217 if (command == null) { 2218 break; 2219 } 2220 if (!command.hasBlockName()) { 2221 msg = ts.setNamedBean(command, (String) value); 2222 } else if (command.equals(Command.NOOP)) { 2223 if (!((String) value).equals(ts.getBeanDisplayName())) { 2224 msg = Bundle.getMessage("cannotChangeBlock", (String) value); 2225 } 2226 } else { 2227 NamedBeanHandle<?> bh = getPreviousBlockHandle(row); 2228 if (bh != null) { 2229 String name = bh.getBean().getDisplayName(); 2230 if (!name.equals(value)) { 2231 msg = Bundle.getMessage("commandInBlock", name); 2232 ts.setNamedBeanHandle(bh); 2233 _dirty = true; 2234 } 2235 } 2236 } 2237 break; 2238 case SPEED_COLUMN: 2239 break; 2240 default: 2241 } 2242 if (msg != null) { 2243 showWarning(msg); 2244 } else { 2245 fireTableRowsUpdated(row, row); 2246 } 2247 } 2248 2249 private NamedBeanHandle<? extends NamedBean> getPreviousBlockHandle(int row) { 2250 for (int i = row; i > 0; i--) { 2251 NamedBeanHandle<? extends NamedBean> bh = _throttleCommands.get(i - 1).getNamedBeanHandle(); 2252 if (bh != null && (bh.getBean() instanceof OBlock)) { 2253 return bh; 2254 } 2255 } 2256 return null; 2257 } 2258 2259 } 2260 2261 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WarrantFrame.class); 2262 2263}