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