001package jmri.jmrit.dispatcher; 002 003import java.awt.BorderLayout; 004import java.awt.Dimension; 005import java.awt.FlowLayout; 006import java.awt.event.ActionEvent; 007import java.util.ArrayList; 008 009import javax.swing.BoxLayout; 010import javax.swing.ButtonGroup; 011import javax.swing.JButton; 012import javax.swing.JCheckBoxMenuItem; 013import javax.swing.JLabel; 014import javax.swing.JMenu; 015import javax.swing.JMenuBar; 016import javax.swing.JPanel; 017import javax.swing.JRadioButton; 018import javax.swing.JScrollPane; 019import javax.swing.JSeparator; 020import javax.swing.JSlider; 021import javax.swing.JTextField; 022 023import java.beans.PropertyChangeEvent; 024 025import javax.swing.JToolBar; 026import javax.swing.event.AncestorEvent; 027import javax.swing.event.AncestorListener; 028import javax.swing.plaf.basic.BasicToolBarUI; 029 030import jmri.Block; 031import jmri.Throttle; 032import jmri.jmrit.roster.RosterEntry; 033import jmri.util.JmriJFrame; 034import jmri.util.swing.JmriJOptionPane; 035 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039/** 040 * AutoTrainsFrame provides a user interface to trains that are running 041 * automatically under Dispatcher. 042 * <p> 043 * There is only one AutoTrains window. AutoTrains are added and deleted from 044 * this window as they are added or terminated. 045 * <p> 046 * This file is part of JMRI. 047 * <p> 048 * JMRI is open source software; you can redistribute it and/or modify it under 049 * the terms of version 2 of the GNU General Public License as published by the 050 * Free Software Foundation. See the "COPYING" file for a copy of this license. 051 * <p> 052 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 053 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 054 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 055 * 056 * @author Dave Duchamp Copyright (C) 2010 057 */ 058public class AutoTrainsFrame extends jmri.util.JmriJFrame { 059 060 public AutoTrainsFrame(DispatcherFrame disp) { 061 super(false, true); 062 initializeAutoTrainsWindow(); 063 } 064 065 // instance variables 066 private final ArrayList<AutoActiveTrain> _autoTrainsList = new ArrayList<>(); 067 //Keep track of throttle and listeners to update frame with their current state. 068 069 // accessor functions 070 public ArrayList<AutoActiveTrain> getAutoTrainsList() { 071 return _autoTrainsList; 072 } 073 074 /** 075 * Creates and initializes a new control of type AutoTrainControl 076 * @param autoActiveTrain the new train. 077 */ 078 public void addAutoActiveTrain(AutoActiveTrain autoActiveTrain) { 079 if (autoActiveTrain != null) { 080 log.debug("Adding ActiveTrain[{}]",autoActiveTrain.getActiveTrain().getActiveTrainName()); 081 AutoTrainControl atn = new AutoTrainControl(autoActiveTrain); 082 if (!trainsCanBeFloated.isSelected()) { 083 atn.componentJPanel.setFloatable(false); 084 } 085 trainsPanel.add(atn); 086 atn.addPropertyChangeListener("terminated", (PropertyChangeEvent e) -> { 087 AutoTrainControl atnn = (AutoTrainControl) e.getSource(); 088 // must be attached to make it really go away 089 ((BasicToolBarUI) atnn.componentJPanel.getUI()).setFloating(false,null); 090 trainsPanel.remove((AutoTrainControl) e.getSource()); 091 pack(); 092 }); 093 // bit of overkill for when a floater floats and comes back. 094 atn.componentJPanel.addAncestorListener ( new AncestorListener () 095 { 096 @Override 097 public void ancestorAdded ( AncestorEvent event ) 098 { 099 log.trace("ancestorAdded"); 100 pack(); 101 } 102 @Override 103 public void ancestorRemoved ( AncestorEvent event ) 104 { 105 log.trace("ancestorRemoved"); 106 pack(); 107 } 108 @Override 109 public void ancestorMoved ( AncestorEvent event ) 110 { 111 // blank. 112 } 113 } ); 114 pack(); 115 } 116 } 117 118 // variables for AutoTrains window 119 protected JmriJFrame autoTrainsFrame = null; 120 private JPanel trainsPanel; 121 private JScrollPane trainScrollPanel; 122 private JCheckBoxMenuItem frameHasScrollBars = new JCheckBoxMenuItem(Bundle.getMessage("AutoTrainsFrameUseScrollBars")); 123 private JCheckBoxMenuItem trainsCanBeFloated = new JCheckBoxMenuItem(Bundle.getMessage("AutoTrainsFrameAllowFloat")); 124 private JCheckBoxMenuItem frameAlwaysOnTop = new JCheckBoxMenuItem(Bundle.getMessage("AutoTrainsFrameAlwaysOnTop")); 125 private JCheckBoxMenuItem frameOnTopOnSpeedChange = new JCheckBoxMenuItem(Bundle.getMessage("AutoTrainsFrameOnTopOnSpeedChange")); 126 127 jmri.UserPreferencesManager prefMan; 128 129 private void initializeAutoTrainsWindow() { 130 131 prefMan = jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class); 132 frameHasScrollBars.setSelected(prefMan.getSimplePreferenceState(hasScrollBars)); 133 trainsCanBeFloated.setSelected(prefMan.getSimplePreferenceState(canFloat)); 134 frameAlwaysOnTop.setSelected(prefMan.getSimplePreferenceState(alWaysOnTop)); 135 frameOnTopOnSpeedChange.setSelected(prefMan.getSimplePreferenceState(onTopOnSpeedChange)); 136 137 138 autoTrainsFrame = this; 139 autoTrainsFrame.setTitle(Bundle.getMessage("TitleAutoTrains")); 140 trainsPanel = new JPanel(); 141 trainsPanel.setLayout(new BoxLayout(trainsPanel, BoxLayout.Y_AXIS)); 142 JMenuBar menuBar = new JMenuBar(); 143 JMenu optMenu = new JMenu(Bundle.getMessage("MenuOptions")); // NOI18N 144 optMenu.add(frameHasScrollBars); 145 frameHasScrollBars.addActionListener(e -> { 146 setScrollBars(); 147 }); 148 149 optMenu.add(trainsCanBeFloated); 150 trainsCanBeFloated.addActionListener(e -> { 151 for (Object ob : trainsPanel.getComponents()) { 152 if (ob instanceof AutoTrainControl) { 153 AutoTrainControl atnn = (AutoTrainControl) ob; 154 if (trainsCanBeFloated.isSelected()) { 155 atnn.componentJPanel.setFloatable(true); 156 } else { 157 // rejoin floating throttles before banning 158 // floating. 159 ((BasicToolBarUI) atnn.componentJPanel.getUI()).setFloating(false, null); 160 atnn.componentJPanel.setFloatable(false); 161 } 162 } 163 } 164 }); 165 166 optMenu.add(frameAlwaysOnTop); 167 frameAlwaysOnTop.addActionListener(e -> { 168 setAlwaysOnTop(frameAlwaysOnTop.isSelected()); 169 }); 170 171 optMenu.add(frameOnTopOnSpeedChange); 172 frameOnTopOnSpeedChange.addActionListener(e -> { 173 for (Object ob : trainsPanel.getComponents()) { 174 if (ob instanceof AutoTrainControl) { 175 AutoTrainControl atnn = (AutoTrainControl) ob; 176 atnn.setOnTopOnSpeedChange(frameOnTopOnSpeedChange.isSelected()); 177 } 178 } 179 }); 180 181 menuBar.add(optMenu); 182 183 setJMenuBar(menuBar); 184 autoTrainsFrame.addHelpMenu("package.jmri.jmrit.dispatcher.AutoTrains", true); 185 trainsPanel.setLayout(new BoxLayout(trainsPanel, BoxLayout.Y_AXIS)); 186 JPanel pB = new JPanel(); 187 pB.setLayout(new FlowLayout()); 188 JButton stopAllButton = new JButton(Bundle.getMessage("StopAll")); 189 pB.add(stopAllButton); 190 stopAllButton.addActionListener(this::stopAllPressed); 191 stopAllButton.setToolTipText(Bundle.getMessage("StopAllButtonHint")); 192 trainsPanel.add(pB); 193 trainsPanel.add(new JSeparator()); 194 trainsPanel.addComponentListener(this); 195 trainsPanel.setVisible(true); 196 trainsPanel.revalidate(); 197 trainScrollPanel = new JScrollPane(); 198 trainScrollPanel.getViewport().add(trainsPanel); 199 autoTrainsFrame.getContentPane().setLayout(new BoxLayout(autoTrainsFrame.getContentPane(), BoxLayout.Y_AXIS)); 200 autoTrainsFrame.getContentPane().add(trainScrollPanel); 201 setScrollBars(); 202 autoTrainsFrame.getContentPane().revalidate(); 203 autoTrainsFrame.pack(); 204 autoTrainsFrame.setVisible(true); 205 206 } 207 208 private void setScrollBars() { 209 if (frameHasScrollBars.isSelected()) { 210 trainScrollPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 211 trainScrollPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 212 autoTrainsFrame.getContentPane().revalidate(); 213 } else { 214 trainScrollPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 215 trainScrollPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 216 autoTrainsFrame.getContentPane().revalidate(); 217 } 218 } 219 220 private void stopAllPressed(ActionEvent e) { 221 for (Object ob: trainsPanel.getComponents()) { 222 if (ob instanceof AutoTrainControl) { 223 ((AutoTrainControl) ob).stopAll(); 224 } 225 } 226 } 227 228 @Override 229 public void dispose() { 230 if (prefMan!=null) { 231 prefMan.setSimplePreferenceState(hasScrollBars, frameHasScrollBars.isSelected()); 232 prefMan.setSimplePreferenceState(canFloat, trainsCanBeFloated.isSelected()); 233 prefMan.setSimplePreferenceState(hasScrollBars, frameHasScrollBars.isSelected()); 234 prefMan.setSimplePreferenceState(canFloat, trainsCanBeFloated.isSelected()); 235 } 236 super.dispose(); 237 } 238 String hasScrollBars = this.getClass().getName() + ".HasScrollBars"; // NOI18N 239 String canFloat = this.getClass().getName() + ".CanFloat"; // NOI18N 240 String alWaysOnTop = this.getClass().getName() + ".AlWaysOnTop"; // NOI18N 241 String onTopOnSpeedChange = this.getClass().getName() + ".OnTopOnSpeedChange"; // NOI18N 242 class AutoTrainControl extends JPanel { 243 244 private boolean useOnTopOnSpeedChange; 245 246 public AutoTrainControl(AutoActiveTrain autoActiveTrain) { 247 this.autoActiveTrain = autoActiveTrain; 248 activeTrain = autoActiveTrain.getActiveTrain(); 249 activeTrain.addPropertyChangeListener(activeTrainListener = new java.beans.PropertyChangeListener() { 250 @Override 251 public void propertyChange(java.beans.PropertyChangeEvent e) { 252 handleActiveTrainListen(e); 253 } 254 }); 255 rosterEntry = autoActiveTrain.getRosterEntry(); 256 drawComponent(); 257 } 258 259 protected void setOnTopOnSpeedChange(boolean value) { 260 useOnTopOnSpeedChange = value; 261 } 262 263 protected void stopAll() { 264 if (activeTrain.getStatus() != ActiveTrain.STOPPED && 265 activeTrain.getStatus() != ActiveTrain.DONE) { 266 autoActiveTrain.saveSpeedAndDirection(); 267 autoActiveTrain.getAutoEngineer().setHalt(true); 268 autoActiveTrain.setSavedStatus(activeTrain.getStatus()); 269 activeTrain.setStatus(ActiveTrain.STOPPED); 270 } 271 } 272 273 private AutoActiveTrain autoActiveTrain = null; 274 private java.beans.PropertyChangeListener activeTrainListener = null; 275 private java.beans.PropertyChangeListener throttleListener = null; 276 private jmri.Throttle throttle = null; 277 private ActiveTrain activeTrain = null; 278 private RosterEntry rosterEntry = null; 279 280 private JLabel trainLabel; 281 private JLabel throttleStatus; 282 protected JButton stopButton; 283 private JButton resumeAutoRunningButton; 284 private JRadioButton forwardButton; 285 private JRadioButton reverseButton; 286 private JSlider speedSlider; 287 private JButton manualButton; 288 289 private void handleThrottleListen(java.beans.PropertyChangeEvent e) { 290 if (!e.getPropertyName().equals(Throttle.SPEEDSETTING) && !e.getPropertyName().equals(Throttle.ISFORWARD)) { 291 return; // ignore if not speed or direction 292 } 293 updateThrottleDisplay(e); 294 } 295 296 private float lastReportedSpeed; // for display purposes 297 298 /* 299 * Updates screen control throttle. 300 */ 301 private void primeThrottleDisplay() { 302 if (throttle != null) { 303 if (throttle.getIsForward()) { 304 forwardButton.setSelected(true); 305 } else { 306 reverseButton.setSelected(true); 307 } 308 lastReportedSpeed = throttle.getSpeedSetting(); 309 if (speedSlider.isVisible()) { 310 speedSlider.setValue(Math.round(lastReportedSpeed * 100.0f)); 311 } 312 } 313 updateThrottleStatus(); 314 } 315 316 /* 317 * Updates control from events 318 */ 319 private void updateThrottleDisplay(java.beans.PropertyChangeEvent e) { 320 if (throttle != null) { 321 if (e.getPropertyName().equals(Throttle.ISFORWARD)) { 322 if ((boolean) e.getNewValue()) { 323 forwardButton.setSelected(true); 324 } else { 325 reverseButton.setSelected(true); 326 } 327 } else { 328 lastReportedSpeed = (float) e.getNewValue(); 329 if (speedSlider.isVisible()) { 330 speedSlider.setValue(Math.round(lastReportedSpeed * 100.0f)); 331 } 332 } 333 } 334 updateThrottleStatus(); 335 } 336 337 /* 338 * Updates the status words. 339 */ 340 private void updateThrottleStatus() { 341 StringBuilder sb = new StringBuilder(); 342 if (throttle != null && throttleStatus.isVisible()) { 343 if (rosterEntry != null && autoActiveTrain.useSpeedProfile && rosterEntry.getSpeedProfile() != null) { 344 sb.append("" + 345 rosterEntry.getSpeedProfile().convertThrottleSettingToScaleSpeedWithUnits( 346 lastReportedSpeed, 347 forwardButton.isSelected())); 348 } else { 349 sb.append("" + Math.round(throttle.getSpeedSetting() * 100)); 350 sb.append("% "); 351 } 352 if (forwardButton.isSelected()) { 353 sb.append("(fwd)"); 354 } else { 355 sb.append("(rev)"); 356 } 357 throttleStatus.setText(sb.toString()); 358 if (useOnTopOnSpeedChange) { 359 // bring to front without getting focus 360 setAlwaysOnTop(true); 361 setAlwaysOnTop(false); 362 } 363 } else if (throttleStatus.isVisible()) { 364 throttleStatus.setText("No Throttle"); 365 } 366 } 367 368 private void handleActiveTrainListen(java.beans.PropertyChangeEvent e) { 369 if (e.getNewValue() != null) { 370 log.trace("Property[{}] newValue[{}]",e.getPropertyName(),e.getNewValue()); 371 } else { 372 log.trace("Property[{}] newValue[{}]",e.getPropertyName(),"NULL"); 373 } 374 if (e.getPropertyName().equals("mode")) { 375 int newValue = ((Integer) e.getNewValue()).intValue(); 376 int oldValue = ((Integer) e.getOldValue()).intValue(); 377 if (newValue == ActiveTrain.DISPATCHED) { 378 stopButton.setVisible(false); 379 manualButton.setVisible(false); 380 resumeAutoRunningButton.setVisible(true); 381 forwardButton.setVisible(false); 382 reverseButton.setVisible(false); 383 speedSlider.setVisible(false); 384 throttleStatus.setVisible(false); 385 jmri.InstanceManager.throttleManagerInstance().removeListener(throttle.getLocoAddress(), 386 throttleListener); 387 } else if (newValue == ActiveTrain.AUTOMATIC) { 388 log.trace("[{}]:Set auto", autoActiveTrain.getActiveTrain().getActiveTrainName()); 389 if (throttle == null && autoActiveTrain.getThrottle() != null 390 || oldValue == ActiveTrain.DISPATCHED) { 391 log.trace("[{}]:Set new throttle", autoActiveTrain.getActiveTrain().getActiveTrainName()); 392 throttle = autoActiveTrain.getThrottle(); 393 throttleListener = new java.beans.PropertyChangeListener() { 394 @Override 395 public void propertyChange(java.beans.PropertyChangeEvent e) { 396 handleThrottleListen(e); 397 } 398 }; 399 jmri.InstanceManager.throttleManagerInstance().attachListener(throttle.getLocoAddress(), throttleListener); 400 rosterEntry = autoActiveTrain.getRosterEntry(); 401 setStatusLabelWidth(); 402 stopButton.setText(Bundle.getMessage("StopButton")); 403 stopButton.setToolTipText(Bundle.getMessage("StopButtonHint")); 404 stopButton.setVisible(true); 405 manualButton.setText(Bundle.getMessage("ToManualButton")); 406 manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint")); 407 manualButton.setVisible(true); 408 resumeAutoRunningButton.setVisible(false); 409 forwardButton.setVisible(false); 410 reverseButton.setVisible(false); 411 speedSlider.setVisible(false); 412 throttleStatus.setVisible(true); 413 primeThrottleDisplay(); 414 } 415 } else if ((int) e.getNewValue() == ActiveTrain.TERMINATED) { 416 if (throttle != null && throttleListener != null) { 417 throttle.removePropertyChangeListener(throttleListener); 418 throttle = null; 419 } 420 activeTrain.removePropertyChangeListener(activeTrainListener); 421 // please someone stop me before I do something silly 422 firePropertyChange("terminated", null, null); 423 } 424 } else if (e.getPropertyName().equals("status")) { 425 log.debug("NewStatus[{}]", e.getNewValue()); 426 if ((int) e.getNewValue() == ActiveTrain.STOPPED) { 427 stopButton.setText(Bundle.getMessage("ResumeButton")); 428 stopButton.setToolTipText(Bundle.getMessage("ResumeButtonHint")); 429 stopButton.setVisible(true); 430 } else if ((int) e.getNewValue() == ActiveTrain.RUNNING || 431 (int) e.getNewValue() == ActiveTrain.WAITING || 432 (int) e.getNewValue() == ActiveTrain.READY ) { 433 log.trace("[{}]:Set auto STATUS RUNNING", autoActiveTrain.getActiveTrain().getActiveTrainName()); 434 if (throttle == null && autoActiveTrain.getThrottle() != null) { 435 log.debug("[{}]:Set new throttle", autoActiveTrain.getActiveTrain().getActiveTrainName()); 436 throttle = autoActiveTrain.getThrottle(); 437 throttleListener = new java.beans.PropertyChangeListener() { 438 @Override 439 public void propertyChange(java.beans.PropertyChangeEvent e) { 440 handleThrottleListen(e); 441 } 442 }; 443 jmri.InstanceManager.throttleManagerInstance().attachListener(throttle.getLocoAddress(), throttleListener); 444 rosterEntry = autoActiveTrain.getRosterEntry(); 445 setStatusLabelWidth(); 446 } 447 stopButton.setText(Bundle.getMessage("StopButton")); 448 stopButton.setToolTipText(Bundle.getMessage("StopButtonHint")); 449 stopButton.setVisible(true); 450 manualButton.setText(Bundle.getMessage("ToManualButton")); 451 manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint")); 452 manualButton.setVisible(true); 453 resumeAutoRunningButton.setVisible(false); 454 forwardButton.setVisible(false); 455 reverseButton.setVisible(false); 456 speedSlider.setVisible(false); 457 throttleStatus.setVisible(true); 458 primeThrottleDisplay(); 459 } else if ((int) e.getNewValue() == ActiveTrain.DONE) { 460 stopButton.setText(Bundle.getMessage("RestartButton")); 461 stopButton.setToolTipText(Bundle.getMessage("RestartButtonHint")); 462 stopButton.setVisible(true); 463 } else { 464 log.debug("Ignored newstatus[{}]", e.getNewValue()); 465 } 466 } 467 pack(); 468 } 469 470 public void manualAutoTrain() { 471 if (activeTrain.getMode() == ActiveTrain.AUTOMATIC) { 472 activeTrain.setMode(ActiveTrain.MANUAL); 473 manualButton.setText(Bundle.getMessage("ToAutoButton")); 474 manualButton.setToolTipText(Bundle.getMessage("ToAutoButtonHint")); 475 forwardButton.setVisible(true); 476 reverseButton.setVisible(true); 477 speedSlider.setVisible(true); 478 if (autoActiveTrain.getAutoEngineer() != null) { 479 autoActiveTrain.saveSpeedAndDirection(); 480 autoActiveTrain.getAutoEngineer().setHalt(true); 481 autoActiveTrain.setTargetSpeed(0.0f); 482 autoActiveTrain.waitUntilStopped(); 483 autoActiveTrain.getAutoEngineer().setHalt(false); 484 if (throttle.getIsForward() ) { 485 forwardButton.setSelected(true); 486 } else { 487 reverseButton.setSelected(true); 488 } 489 } 490 491 } else if (activeTrain.getMode() == ActiveTrain.MANUAL) { 492 activeTrain.setMode(ActiveTrain.AUTOMATIC); 493 manualButton.setText(Bundle.getMessage("ToManualButton")); 494 manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint")); 495 manualButton.setVisible(true); 496 forwardButton.setVisible(false); 497 reverseButton.setVisible(false); 498 speedSlider.setVisible(false); 499 autoActiveTrain.restoreSavedSpeedAndDirection(); 500 // autoActiveTrain.setForward(!autoActiveTrain.getRunInReverse()); 501 if ((activeTrain.getStatus() == ActiveTrain.RUNNING) || 502 (activeTrain.getStatus() == ActiveTrain.WAITING)) { 503 autoActiveTrain.setSpeedBySignal(); 504 } 505 } 506 pack(); 507 } 508 509 private JToolBar componentJPanel; 510 511 private void drawComponent() { 512 513 componentJPanel = new JToolBar(); 514 componentJPanel.setLayout(new FlowLayout()); 515 componentJPanel.setFloatable(true); 516 trainLabel = new JLabel(autoActiveTrain.getActiveTrain().getTrainName()); 517 trainLabel.setVisible(true); 518 componentJPanel.add(trainLabel); 519 stopButton = new JButton(Bundle.getMessage("ResumeButton")); 520 componentJPanel.add(stopButton); 521 stopButton.addActionListener(e -> stopResume()); 522 manualButton = new JButton(Bundle.getMessage("ToManualButton")); 523 componentJPanel.add(manualButton); 524 manualButton.addActionListener(e -> manualAutoTrain()); 525 resumeAutoRunningButton = new JButton(Bundle.getMessage("ResumeAutoButton")); 526 componentJPanel.add(resumeAutoRunningButton); 527 resumeAutoRunningButton.addActionListener(e -> resumeAutoOperation()); 528 resumeAutoRunningButton.setVisible(false); 529 resumeAutoRunningButton.setToolTipText(Bundle.getMessage("ResumeAutoButtonHint")); 530 ButtonGroup directionGroup = new ButtonGroup(); 531 forwardButton = new JRadioButton(Bundle.getMessage("ForwardRadio")); 532 componentJPanel.add(forwardButton); 533 forwardButton.addActionListener(e -> directionButton()); 534 directionGroup.add(forwardButton); 535 reverseButton = new JRadioButton(Bundle.getMessage("ReverseRadio")); 536 componentJPanel.add(reverseButton); 537 reverseButton.addActionListener(e -> directionButton()); 538 directionGroup.add(reverseButton); 539 speedSlider = new JSlider(0, 100, 0); 540 speedSlider.setPreferredSize(new Dimension(100, 20)); 541 componentJPanel.add(speedSlider); 542 speedSlider.addChangeListener(e -> { 543 if (speedSlider.isVisible()) { 544 int val = ((JSlider) (e.getSource())).getValue(); 545 float speedValue = val * 0.01f; 546 // bypass auto-engineer limits, ramping etc 547 // when in manual. 548 autoActiveTrain.getThrottle().setSpeedSetting(speedValue); 549 } 550 }); 551 552 throttleStatus = new JLabel(); 553 // prevent JFrame to resize on each % change - temporary size for initialization 554 throttleStatus.setPreferredSize(new Dimension(100, 20)); 555 throttleStatus.setText("Speed Unknown"); 556 componentJPanel.add(throttleStatus); 557 componentJPanel.revalidate(); 558 add(componentJPanel, BorderLayout.EAST); 559 pack(); 560 } 561 562 /* 563 * Using dummy strings get max size of the statustext 564 */ 565 private void setStatusLabelWidth() { 566 if (rosterEntry!=null && autoActiveTrain.getUseSpeedProfile()) { 567 throttleStatus.setPreferredSize( 568 new JTextField(20).getPreferredSize()); 569 } else { 570 throttleStatus.setPreferredSize( 571 new JTextField(10).getPreferredSize()); 572 } 573 } 574 public void stopResume() { 575 if (autoActiveTrain.getAutoEngineer() != null) { 576 ActiveTrain at = autoActiveTrain.getActiveTrain(); 577 if (at.getStatus() == ActiveTrain.STOPPED) { 578 log.trace("Train Is Stopped - Resume"); 579 if (autoActiveTrain.getCurrentBlock().getState() != Block.OCCUPIED) { 580 JmriJOptionPane.showMessageDialog( 581 this, 582 Bundle.getMessage("AutoTrainsFramePleaseMoveTrain",autoActiveTrain.getCurrentBlock().getDisplayName()), 583 Bundle.getMessage("ResumeAutoButton"), 584 JmriJOptionPane.INFORMATION_MESSAGE 585 ); 586 return; 587 } 588 Block b = autoActiveTrain.isBlockAhead(); 589 if (b != null) { 590 JmriJOptionPane.showMessageDialog( 591 this, 592 Bundle.getMessage("AutoTrainsFrameUnExplainedOccupancy", 593 b.getDisplayName(), 594 autoActiveTrain.getNextBlock()), 595 Bundle.getMessage("ResumeAutoButton"), 596 JmriJOptionPane.INFORMATION_MESSAGE 597 ); 598 return; 599 } 600 601 boolean tmpIsForward = true; 602 if ( autoActiveTrain.getRunInReverse() != at.isTransitReversed()) { 603 tmpIsForward = false; 604 } 605 Object[] options = {Bundle.getMessage("AutoTrainsFrameUseImpliedDirection",getDirString(tmpIsForward)), 606 Bundle.getMessage("AutoTrainsFrameRestoreSaved",getDirString(autoActiveTrain.getSavedDirection())), 607 Bundle.getMessage("AutoTrainsFrameUseCurrent",getDirString(autoActiveTrain.getForward())) }; 608 if ( tmpIsForward != autoActiveTrain.getSavedDirection() || 609 tmpIsForward != autoActiveTrain.getForward()) { 610 int retval = JmriJOptionPane.showOptionDialog(this, 611 Bundle.getMessage("AutoTrainsFrameWhichDirectionToUse"), 612 Bundle.getMessage("AutoTrainsFrameDirectionConflict"), 613 JmriJOptionPane.YES_NO_OPTION, 614 JmriJOptionPane.QUESTION_MESSAGE, null, options, options[1]); 615 switch (retval) { 616 case 0: 617 autoActiveTrain.setEngineDirection(tmpIsForward); 618 break; 619 case 1: 620 autoActiveTrain.setEngineDirection(autoActiveTrain.getSavedDirection()); 621 break; 622 case 2: 623 autoActiveTrain.setEngineDirection(autoActiveTrain.getForward()); 624 break; 625 default: 626 // do nothing. 627 log.info("rturneded[{}]",retval); 628 } 629 } 630 autoActiveTrain.getAutoEngineer().setHalt(false); 631 at.setStatus(autoActiveTrain.getSavedStatus()); 632 if (at.getStatus() == ActiveTrain.STOPPED) { 633 at.setStatus(ActiveTrain.WAITING); 634 } 635 if ((at.getStatus() == ActiveTrain.RUNNING) || (at.getStatus() == ActiveTrain.WAITING)) { 636 autoActiveTrain.setSpeedBySignal(); 637 } 638 } else if (at.getStatus() == ActiveTrain.READY) { 639 handleActiveTrainListen(new java.beans.PropertyChangeEvent (this,"status", Integer.valueOf(0), Integer.valueOf(ActiveTrain.READY))); 640 } else if (at.getStatus() == ActiveTrain.DONE) { 641 log.trace("Train Is Done - Restart"); 642 // restart 643 at.allocateAFresh(); 644 at.restart(); 645 } else { 646 log.trace("Process As Stop"); 647 // stop 648 autoActiveTrain.saveSpeedAndDirection(); 649 autoActiveTrain.getAutoEngineer().setHalt(true); 650 autoActiveTrain.setSavedStatus(at.getStatus()); 651 at.setStatus(ActiveTrain.STOPPED); 652 speedSlider.setValue(0); 653 } 654 } else { 655 log.error("unexpected null autoEngineer"); 656 } 657 } 658 659 private String getDirString(boolean isFwd) { 660 return isFwd ? Bundle.getMessage("Fwd") : Bundle.getMessage("Rev"); 661 } 662 663 public void resumeAutoOperation() { 664 autoActiveTrain.resumeAutomaticRunning(); 665 } 666 667 public void directionButton() { 668 ActiveTrain at = autoActiveTrain.getActiveTrain(); 669 if (at.getMode() == ActiveTrain.MANUAL) { 670 autoActiveTrain.setForward(forwardButton.isSelected()); 671 } else { 672 log.debug(" {}:Ignored direction button change, not in manual mode", at.getTrainName()); 673 } 674 } 675 } 676 677 private static final Logger log = LoggerFactory.getLogger(AutoTrainsFrame.class); 678 679} 680 681