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                if (newValue == ActiveTrain.DISPATCHED) {
377                    stopButton.setVisible(false);
378                    manualButton.setVisible(false);
379                    resumeAutoRunningButton.setVisible(true);
380                    forwardButton.setVisible(false);
381                    reverseButton.setVisible(false);
382                    speedSlider.setVisible(false);
383                    throttleStatus.setVisible(false);
384                    jmri.InstanceManager.throttleManagerInstance().removeListener(throttle.getLocoAddress(),
385                            throttleListener);
386                } else if (newValue == ActiveTrain.AUTOMATIC) {
387                    log.trace("[{}]:Set auto", autoActiveTrain.getActiveTrain().getActiveTrainName());
388                    if (throttle == null && autoActiveTrain.getThrottle() != null) {
389                        log.trace("[{}]:Set new throttle", autoActiveTrain.getActiveTrain().getActiveTrainName());
390                        throttle = autoActiveTrain.getThrottle();
391                        throttleListener = new java.beans.PropertyChangeListener() {
392                            @Override
393                            public void propertyChange(java.beans.PropertyChangeEvent e) {
394                                handleThrottleListen(e);
395                            }
396                        };
397                        jmri.InstanceManager.throttleManagerInstance().attachListener(throttle.getLocoAddress(), throttleListener);
398                        rosterEntry = autoActiveTrain.getRosterEntry();
399                        setStatusLabelWidth();
400                        stopButton.setText(Bundle.getMessage("StopButton"));
401                        stopButton.setToolTipText(Bundle.getMessage("StopButtonHint"));
402                        stopButton.setVisible(true);
403                        manualButton.setText(Bundle.getMessage("ToManualButton"));
404                        manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint"));
405                        manualButton.setVisible(true);
406                        resumeAutoRunningButton.setVisible(false);
407                        forwardButton.setVisible(false);
408                        reverseButton.setVisible(false);
409                        speedSlider.setVisible(false);
410                        throttleStatus.setVisible(true);
411                        primeThrottleDisplay();
412                    }
413                } else if ((int) e.getNewValue() == ActiveTrain.TERMINATED) {
414                    if (throttle != null && throttleListener != null) {
415                        throttle.removePropertyChangeListener(throttleListener);
416                        throttle = null;
417                    }
418                    activeTrain.removePropertyChangeListener(activeTrainListener);
419                    // please someone stop me before I do something silly
420                    firePropertyChange("terminated", null, null);
421                }
422            } else if (e.getPropertyName().equals("status")) {
423                log.debug("NewStatus[{}]", e.getNewValue());
424                if ((int) e.getNewValue() == ActiveTrain.STOPPED) {
425                    stopButton.setText(Bundle.getMessage("ResumeButton"));
426                    stopButton.setToolTipText(Bundle.getMessage("ResumeButtonHint"));
427                    stopButton.setVisible(true);
428                } else if ((int) e.getNewValue() == ActiveTrain.RUNNING ||
429                        (int) e.getNewValue() == ActiveTrain.WAITING ||
430                        (int) e.getNewValue() == ActiveTrain.READY ) {
431                    log.trace("[{}]:Set auto STATUS RUNNING", autoActiveTrain.getActiveTrain().getActiveTrainName());
432                    if (throttle == null && autoActiveTrain.getThrottle() != null) {
433                        log.debug("[{}]:Set new throttle", autoActiveTrain.getActiveTrain().getActiveTrainName());
434                        throttle = autoActiveTrain.getThrottle();
435                        throttleListener = new java.beans.PropertyChangeListener() {
436                            @Override
437                            public void propertyChange(java.beans.PropertyChangeEvent e) {
438                                handleThrottleListen(e);
439                            }
440                        };
441                        jmri.InstanceManager.throttleManagerInstance().attachListener(throttle.getLocoAddress(), throttleListener);
442                        rosterEntry = autoActiveTrain.getRosterEntry();
443                        setStatusLabelWidth();
444                    }
445                    stopButton.setText(Bundle.getMessage("StopButton"));
446                    stopButton.setToolTipText(Bundle.getMessage("StopButtonHint"));
447                    stopButton.setVisible(true);
448                    manualButton.setText(Bundle.getMessage("ToManualButton"));
449                    manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint"));
450                    manualButton.setVisible(true);
451                    resumeAutoRunningButton.setVisible(false);
452                    forwardButton.setVisible(false);
453                    reverseButton.setVisible(false);
454                    speedSlider.setVisible(false);
455                    throttleStatus.setVisible(true);
456                    primeThrottleDisplay();
457                } else if ((int) e.getNewValue() == ActiveTrain.DONE) {
458                    stopButton.setText(Bundle.getMessage("RestartButton"));
459                    stopButton.setToolTipText(Bundle.getMessage("RestartButtonHint"));
460                    stopButton.setVisible(true);
461                } else {
462                    log.debug("Ignored newstatus[{}]", e.getNewValue());
463                }
464            }
465            pack();
466        }
467
468        public void manualAutoTrain() {
469            if (activeTrain.getMode() == ActiveTrain.AUTOMATIC) {
470                activeTrain.setMode(ActiveTrain.MANUAL);
471                manualButton.setText(Bundle.getMessage("ToAutoButton"));
472                manualButton.setToolTipText(Bundle.getMessage("ToAutoButtonHint"));
473                forwardButton.setVisible(true);
474                reverseButton.setVisible(true);
475                speedSlider.setVisible(true);
476                if (autoActiveTrain.getAutoEngineer() != null) {
477                    autoActiveTrain.saveSpeedAndDirection();
478                    autoActiveTrain.getAutoEngineer().setHalt(true);
479                    autoActiveTrain.setTargetSpeed(0.0f);
480                    autoActiveTrain.waitUntilStopped();
481                    autoActiveTrain.getAutoEngineer().setHalt(false);
482                    if (throttle.getIsForward() ) {
483                        forwardButton.setSelected(true);
484                    } else {
485                        reverseButton.setSelected(true);
486                    }
487                }
488
489            } else if (activeTrain.getMode() == ActiveTrain.MANUAL) {
490                activeTrain.setMode(ActiveTrain.AUTOMATIC);
491                manualButton.setText(Bundle.getMessage("ToManualButton"));
492                manualButton.setToolTipText(Bundle.getMessage("ToManualButtonHint"));
493                manualButton.setVisible(true);
494                forwardButton.setVisible(false);
495                reverseButton.setVisible(false);
496                speedSlider.setVisible(false);
497                autoActiveTrain.restoreSavedSpeedAndDirection();
498                // autoActiveTrain.setForward(!autoActiveTrain.getRunInReverse());
499                if ((activeTrain.getStatus() == ActiveTrain.RUNNING) ||
500                        (activeTrain.getStatus() == ActiveTrain.WAITING)) {
501                    autoActiveTrain.setSpeedBySignal();
502                }
503            }
504            pack();
505        }
506
507        private JToolBar componentJPanel;
508
509        private void drawComponent() {
510
511            componentJPanel = new JToolBar();
512            componentJPanel.setLayout(new FlowLayout());
513            componentJPanel.setFloatable(true);
514            trainLabel = new JLabel(autoActiveTrain.getActiveTrain().getTrainName());
515            trainLabel.setVisible(true);
516            componentJPanel.add(trainLabel);
517            stopButton = new JButton(Bundle.getMessage("ResumeButton"));
518            componentJPanel.add(stopButton);
519            stopButton.addActionListener(e -> stopResume());
520            manualButton = new JButton(Bundle.getMessage("ToManualButton"));
521            componentJPanel.add(manualButton);
522            manualButton.addActionListener(e -> manualAutoTrain());
523            resumeAutoRunningButton = new JButton(Bundle.getMessage("ResumeAutoButton"));
524            componentJPanel.add(resumeAutoRunningButton);
525            resumeAutoRunningButton.addActionListener(e -> resumeAutoOperation());
526            resumeAutoRunningButton.setVisible(false);
527            resumeAutoRunningButton.setToolTipText(Bundle.getMessage("ResumeAutoButtonHint"));
528            ButtonGroup directionGroup = new ButtonGroup();
529            forwardButton = new JRadioButton(Bundle.getMessage("ForwardRadio"));
530            componentJPanel.add(forwardButton);
531            forwardButton.addActionListener(e -> directionButton());
532            directionGroup.add(forwardButton);
533            reverseButton = new JRadioButton(Bundle.getMessage("ReverseRadio"));
534            componentJPanel.add(reverseButton);
535            reverseButton.addActionListener(e -> directionButton());
536            directionGroup.add(reverseButton);
537            speedSlider = new JSlider(0, 100, 0);
538            speedSlider.setPreferredSize(new Dimension(100, 20));
539            componentJPanel.add(speedSlider);
540            speedSlider.addChangeListener(e -> {
541                if (speedSlider.isVisible()) {
542                    int val = ((JSlider) (e.getSource())).getValue();
543                    float speedValue = val * 0.01f;
544                    // bypass auto-engineer limits, ramping etc
545                    // when in manual.
546                    autoActiveTrain.getThrottle().setSpeedSetting(speedValue);
547                }
548            });
549
550            throttleStatus = new JLabel();
551            // prevent JFrame to resize on each % change - temporary size for initialization
552            throttleStatus.setPreferredSize(new Dimension(100, 20));
553            throttleStatus.setText("Speed Unknown");
554            componentJPanel.add(throttleStatus);
555            componentJPanel.revalidate();
556            add(componentJPanel, BorderLayout.EAST);
557            pack();
558        }
559
560        /*
561         * Using dummy strings get max size of the statustext
562         */
563        private void setStatusLabelWidth() {
564            if (rosterEntry!=null && autoActiveTrain.getUseSpeedProfile()) {
565                throttleStatus.setPreferredSize(
566                        new JTextField(20).getPreferredSize());
567            } else {
568                throttleStatus.setPreferredSize(
569                        new JTextField(10).getPreferredSize());
570            }
571        }
572        public void stopResume() {
573            if (autoActiveTrain.getAutoEngineer() != null) {
574                ActiveTrain at = autoActiveTrain.getActiveTrain();
575                if (at.getStatus() == ActiveTrain.STOPPED) {
576                    log.trace("Train Is Stopped - Resume");
577                    if (autoActiveTrain.getCurrentBlock().getState() != Block.OCCUPIED) {
578                        JmriJOptionPane.showMessageDialog(
579                                this,
580                                Bundle.getMessage("AutoTrainsFramePleaseMoveTrain",autoActiveTrain.getCurrentBlock().getDisplayName()),
581                                Bundle.getMessage("ResumeAutoButton"),
582                                JmriJOptionPane.INFORMATION_MESSAGE
583                            );
584                        return;
585                    }
586                    Block b = autoActiveTrain.isBlockAhead();
587                    if (b != null) {
588                        JmriJOptionPane.showMessageDialog(
589                                this,
590                                Bundle.getMessage("AutoTrainsFrameUnExplainedOccupancy",
591                                        b.getDisplayName(),
592                                        autoActiveTrain.getNextBlock()),
593                                Bundle.getMessage("ResumeAutoButton"),
594                                JmriJOptionPane.INFORMATION_MESSAGE
595                            );
596                        return;
597                    }
598
599                    boolean tmpIsForward = true;
600                    if ( autoActiveTrain.getRunInReverse() !=  at.isTransitReversed()) {
601                        tmpIsForward = false;
602                    }
603                    Object[] options = {Bundle.getMessage("AutoTrainsFrameUseImpliedDirection",getDirString(tmpIsForward)),
604                            Bundle.getMessage("AutoTrainsFrameRestoreSaved",getDirString(autoActiveTrain.getSavedDirection())),
605                            Bundle.getMessage("AutoTrainsFrameUseCurrent",getDirString(autoActiveTrain.getForward())) };
606                    if ( tmpIsForward != autoActiveTrain.getSavedDirection() ||
607                            tmpIsForward != autoActiveTrain.getForward()) {
608                        int retval = JmriJOptionPane.showOptionDialog(this,
609                                Bundle.getMessage("AutoTrainsFrameWhichDirectionToUse"),
610                                Bundle.getMessage("AutoTrainsFrameDirectionConflict"),
611                                JmriJOptionPane.YES_NO_OPTION,
612                                JmriJOptionPane.QUESTION_MESSAGE, null, options, options[1]);
613                        switch (retval) {
614                            case 0:
615                                autoActiveTrain.setEngineDirection(tmpIsForward);
616                                break;
617                            case 1:
618                                autoActiveTrain.setEngineDirection(autoActiveTrain.getSavedDirection());
619                                break;
620                            case 2:
621                                autoActiveTrain.setEngineDirection(autoActiveTrain.getForward());
622                                break;
623                            default:
624                                // do nothing.
625                                log.info("rturneded[{}]",retval);
626                        }
627                    }
628                    autoActiveTrain.getAutoEngineer().setHalt(false);
629                    at.setStatus(autoActiveTrain.getSavedStatus());
630                    if (at.getStatus() == ActiveTrain.STOPPED) {
631                        at.setStatus(ActiveTrain.WAITING);
632                    }
633                    if ((at.getStatus() == ActiveTrain.RUNNING) || (at.getStatus() == ActiveTrain.WAITING)) {
634                        autoActiveTrain.setSpeedBySignal();
635                    }
636                } else if (at.getStatus() == ActiveTrain.READY) {
637                    handleActiveTrainListen(new java.beans.PropertyChangeEvent (this,"status", Integer.valueOf(0), Integer.valueOf(ActiveTrain.READY)));
638                } else if (at.getStatus() == ActiveTrain.DONE) {
639                    log.trace("Train Is Done - Restart");
640                    // restart
641                    at.allocateAFresh();
642                    at.restart();
643                } else {
644                    log.trace("Process As Stop");
645                    // stop
646                    autoActiveTrain.saveSpeedAndDirection();
647                    autoActiveTrain.getAutoEngineer().setHalt(true);
648                    autoActiveTrain.setSavedStatus(at.getStatus());
649                    at.setStatus(ActiveTrain.STOPPED);
650                    speedSlider.setValue(0);
651                }
652            } else {
653                log.error("unexpected null autoEngineer");
654            }
655        }
656
657        private String getDirString(boolean isFwd) {
658            return isFwd ? Bundle.getMessage("Fwd") : Bundle.getMessage("Rev");
659        }
660
661        public void resumeAutoOperation() {
662            autoActiveTrain.resumeAutomaticRunning();
663        }
664
665        public void directionButton() {
666            ActiveTrain at = autoActiveTrain.getActiveTrain();
667            if (at.getMode() == ActiveTrain.MANUAL) {
668                autoActiveTrain.setForward(forwardButton.isSelected());
669            } else {
670                log.debug(" {}:Ignored direction button change, not in manual mode", at.getTrainName());
671            }
672        }
673    }
674
675    private final static Logger log = LoggerFactory.getLogger(AutoTrainsFrame.class);
676
677}
678
679