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