001package jmri.jmrix.sprog.sprogslotmon;
002
003import java.awt.Dimension;
004import java.awt.FlowLayout;
005import java.awt.event.ActionEvent;
006import java.awt.event.ActionListener;
007import javax.swing.BoxLayout;
008import javax.swing.JButton;
009import javax.swing.JMenuBar;
010import javax.swing.JPanel;
011import javax.swing.JScrollPane;
012import javax.swing.JTable;
013import javax.swing.JTextArea;
014import javax.swing.table.TableRowSorter;
015import jmri.jmrix.sprog.SprogListener;
016import jmri.jmrix.sprog.SprogMessage;
017import jmri.jmrix.sprog.SprogReply;
018import jmri.jmrix.sprog.SprogSystemConnectionMemo;
019import jmri.jmrix.sprog.SprogTrafficController;
020import jmri.util.swing.JmriMouseEvent;
021import jmri.util.swing.JmriMouseListener;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024
025/**
026 * Frame providing a command station slot manager.
027 * <p>
028 * May-17 Modified to a SprogListener to handle status replies.
029 * <p>
030 * Jan-18 Moved status request generation here, based on a timer.
031 *
032 * @author Bob Jacobsen Copyright (C) 2001
033 * @author Andrew Crosland (C) 2006 ported to SPROG 2008
034 */
035public class SprogSlotMonFrame extends jmri.util.JmriJFrame implements SprogListener {
036
037    /**
038     * Controls whether not-in-use slots are shown.
039     */
040    javax.swing.JCheckBox showAllCheckBox = new javax.swing.JCheckBox();
041
042    JButton estopAllButton = new JButton(Bundle.getMessage("ButtonEstopAll"));
043    SprogSlotMonDataModel slotModel = null;
044
045    JTable slotTable;
046    JScrollPane slotScroll;
047
048    JTextArea status = new JTextArea(Bundle.getMessage("TrackCurrentXString", "---"));
049
050    SprogSystemConnectionMemo _memo = null;
051    private SprogTrafficController tc = null;
052
053    private static final int STATUS_PERIOD = 500;
054    javax.swing.Timer timer = null;
055
056    public SprogSlotMonFrame(SprogSystemConnectionMemo memo) {
057        super();
058        _memo = memo;
059
060        tc = memo.getSprogTrafficController();
061        tc.addSprogListener(this);
062
063        slotModel = new SprogSlotMonDataModel(memo.getNumSlots(), 8, _memo);
064
065        slotTable = new JTable(slotModel);
066        slotTable.setRowSorter(new TableRowSorter<>(slotModel));
067        slotScroll = new JScrollPane(slotTable);
068
069        // configure items for GUI
070        showAllCheckBox.setText(Bundle.getMessage("ButtonShowUnusedSlots"));
071        showAllCheckBox.setVisible(true);
072        showAllCheckBox.setSelected(true);
073        showAllCheckBox.setToolTipText(Bundle.getMessage("ButtonShowSlotsTooltip"));
074
075        slotModel.configureTable(slotTable);
076
077        // add listener object so checkboxes function
078        showAllCheckBox.addActionListener(new ActionListener() {
079            @Override
080            public void actionPerformed(ActionEvent e) {
081                slotModel.showAllSlots(showAllCheckBox.isSelected());
082                slotModel.fireTableDataChanged();
083            }
084        });
085
086        // add listener object so stop all button functions
087        estopAllButton.addActionListener(new ActionListener() {
088            @Override
089            public void actionPerformed(ActionEvent e) {
090                log.debug("Estop all button pressed");
091                _memo.getCommandStation().estopAll();
092            }
093        });
094
095        estopAllButton.addMouseListener(JmriMouseListener.adapt(new JmriMouseListener() {
096            @Override
097            public void mousePressed(JmriMouseEvent e) {
098                _memo.getCommandStation().estopAll();
099            }
100
101            @Override
102            public void mouseExited(JmriMouseEvent e) {
103            }
104
105            @Override
106            public void mouseEntered(JmriMouseEvent e) {
107            }
108
109            @Override
110            public void mouseReleased(JmriMouseEvent e) {
111            }
112
113            @Override
114            public void mouseClicked(JmriMouseEvent e) {
115            }
116        }));
117
118        // adjust model to default settings
119        slotModel.showAllSlots(showAllCheckBox.isSelected());
120
121        // general GUI config
122        setTitle(Bundle.getMessage("SprogSlotMonitorTitle"));
123        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
124
125        // install items in GUI
126        JPanel pane1 = new JPanel();
127        pane1.setLayout(new FlowLayout());
128
129        pane1.add(showAllCheckBox);
130        pane1.add(estopAllButton);
131        pane1.add(status);
132
133        getContentPane().add(pane1);
134        getContentPane().add(slotScroll);
135
136        setHelp();
137
138        pack();
139        pane1.setMaximumSize(pane1.getSize());
140        pack();
141
142        startTimer(STATUS_PERIOD);
143    }
144
145    /**
146     * Define system-specific help item
147     */
148    protected void setHelp() {
149        addHelpMenu("package.jmri.jmrix.sprog.sprogslotmon.SprogSlotMonFrame", true);  // NOI18N
150    }
151
152    public void update() {
153        slotModel.fireTableDataChanged();
154    }
155
156    public void updateStatus(String a) {
157        status.setText(Bundle.getMessage("TrackCurrentXString", a));
158    }
159
160    private boolean mShown = false;
161
162    /**
163     * Listen to outgoing messages.
164     *
165     * @param m the sprog message received
166     */
167    @Override
168    public void notifyMessage(SprogMessage m) {
169        // Do nothing
170    }
171
172    /**
173     * Listen for status replies.
174     *
175     * @param m The SprogReply to be handled
176     */
177    @Override
178    public void notifyReply(SprogReply m) {
179        int[] statusA = new int[4];
180        String s = m.toString();
181        log.debug("Reply received: {}", s);
182        if (s.indexOf('S') > -1) {
183            // Handle a status reply
184            log.debug("Status reply");
185            int i = s.indexOf('h');
186            // Double Check that "h" was found in the reply
187            if (i > -1) {
188                int milliAmps = (int) ((Integer.decode("0x" + s.substring(i + 7, i + 11)))
189                        * tc.getAdapterMemo().getSprogType().getCurrentMultiplier());
190                statusA[0] = milliAmps;
191                String ampString;
192                ampString = Float.toString((float) statusA[0] / 1000);
193                updateStatus(ampString);
194            }
195        }
196    }
197
198    @Override
199    public void addNotify() {
200        super.addNotify();
201
202        if (mShown) {
203            return;
204        }
205
206        // resize frame to account for menubar
207        JMenuBar jMenuBar = getJMenuBar();
208        if (jMenuBar != null) {
209            int jMenuBarHeight = jMenuBar.getPreferredSize().height;
210            Dimension dimension = getSize();
211            dimension.height += jMenuBarHeight;
212            setSize(dimension);
213        }
214        mShown = true;
215    }
216
217    @Override
218    public void dispose() {
219        // deregister with the command station.
220        stopTimer();
221        if (slotModel != null) {
222            slotModel.dispose();
223        }
224        slotModel = null;
225        slotTable = null;
226        slotScroll = null;
227        if (tc != null) {
228            tc.removeSprogListener(this);
229        }
230        super.dispose();
231    }
232
233    /**
234     * Internal routine to handle a timeout
235     */
236    synchronized protected void timeout() {
237        Runnable r = () -> {
238            // Send a status request
239            log.debug("Sending status request");
240            tc.sendSprogMessage(SprogMessage.getStatus(), this);
241        };
242        javax.swing.SwingUtilities.invokeLater(r);
243    }
244
245    /**
246     * Internal routine to handle timer starts and restarts
247     *
248     * @param delay timer delay
249     */
250    protected void startTimer(int delay) {
251        log.debug("Restart timer");
252        if (timer == null) {
253            timer = new javax.swing.Timer(delay, (java.awt.event.ActionEvent e) -> {
254                timeout();
255            });
256        }
257        timer.stop();
258        timer.setInitialDelay(delay);
259        timer.setRepeats(true);
260        timer.start();
261    }
262
263    /**
264     * Internal routine to handle timer stop
265     */
266    protected void stopTimer() {
267        log.debug("Stop timer");
268        if (timer != null) {
269            timer.stop();
270        }
271    }
272
273    private final static Logger log = LoggerFactory.getLogger(SprogSlotMonFrame.class);
274
275}