001package jmri.jmrix.cmri.serial.serialmon;
002
003import java.awt.*;
004import java.awt.event.ActionEvent;
005import java.awt.event.ItemEvent;
006import java.awt.event.ItemListener;
007import java.util.ArrayList;
008import javax.swing.*;
009import javax.swing.border.Border;
010import javax.swing.border.TitledBorder;
011import javax.swing.table.*;
012import jmri.jmrix.cmri.CMRISystemConnectionMemo;
013import jmri.jmrix.cmri.serial.SerialNode;
014import jmri.jmrix.cmri.serial.SerialTrafficController;
015
016/**
017 * Frame for a message filter for CMRInet network packets.
018 *
019 * @author  Chuck Catania   Copyright (C) 2016
020 */
021public class SerialFilterFrame extends jmri.util.JmriJFrame {
022
023    ArrayList<SerialNode> monitorNode = new  ArrayList<>();
024
025    // node table pane items
026    protected JPanel nodeEnablePanel = null;
027    protected Border nodeEableBorder = BorderFactory.createEtchedBorder();
028    protected Border nodeEableBorderTitled = BorderFactory.createTitledBorder(nodeEableBorder,"Monitor Nodes",TitledBorder.LEFT,TitledBorder.ABOVE_TOP);
029
030    protected Border packetTypesBorder = BorderFactory.createEtchedBorder();
031    protected Border packetTypesBorderTitled = BorderFactory.createTitledBorder(packetTypesBorder,"Packet Types",TitledBorder.LEFT,TitledBorder.ABOVE_TOP);
032
033    protected Border enabledBorder = BorderFactory.createEtchedBorder();
034    protected Border enabledBorderTitled = BorderFactory.createTitledBorder(enabledBorder,"Select Nodes",TitledBorder.LEFT,TitledBorder.ABOVE_TOP);
035
036    protected Border packetSelectBorder = BorderFactory.createEtchedBorder();
037    protected Border packetSelectBorderTitled = BorderFactory.createTitledBorder(packetSelectBorder,"Select Packets",TitledBorder.LEFT,TitledBorder.ABOVE_TOP);
038
039    protected Border mainButtonsBorder = BorderFactory.createEtchedBorder();
040    protected Border mainButtonsBorderTitled = BorderFactory.createTitledBorder(mainButtonsBorder,"");
041
042    protected JTable nodeTable = null;
043    protected TableModel nodeTableModel = null;
044
045    // button pane items
046    JButton doneButton = new JButton(Bundle.getMessage("DoneButtonText") );
047    JButton haltPollButton = new JButton(Bundle.getMessage("HaltPollButtonText") );
048
049    JButton nodeMonitorAll = new JButton(Bundle.getMessage("AllButtonText") );
050    JButton nodeMonitorNone = new JButton(Bundle.getMessage("NoneButtonText") );
051
052    JButton packetMonitorAll = new JButton(Bundle.getMessage("AllButtonText") );
053    JButton packetMonitorNone = new JButton(Bundle.getMessage("NoneButtonText") );
054
055    // CMRInet packet monitor variables only persistent when running
056    //--------------------------------------------------------------
057    public static final int monPktInit     =  0; // (I) 0x49 Initialize
058    public static final int monPktPoll     =  1; // (P) 0x50 Poll
059    public static final int monPktRead     =  2; // (R) 0x52 Read
060    public static final int monPktTransmit =  3; // (T) 0x54 Transmit
061    public static final int monPktEOT      =  4; // (E) 0x45 EOT
062    public static final int monPktQuery    =  5; // (Q) 0x51 Query
063    public static final int monPktDGread   =  6; // (D) 0x44 Datagram Read
064    public static final int monPktDGwrite  =  7; // (W) 0x57 Datagram Write
065    public static final int monPktDGack    =  8; // (A) 0x41 Datagram Ack
066    public static final int monPktCodeline =  9; // (C) 0x43 Code Line
067    public static final int monPktNMRAmast = 10; // (M) 0x4D NMRA Mast
068    public static final int monPktRFE      = 11; // (?) 0x3F RFE
069/*
070    public static final int monPktRFE      = 12; // RFE
071    public static final int monPktRFE      = 13; // RFE
072    public static final int monPktRFE      = 14; // RFE
073    public static final int monPktRFE      = 15; // RFE
074*/
075    public static final int numMonPkts     = monPktRFE;
076    public static final int lastStdPkt     = monPktTransmit+1;
077    // static final int[] monPktTypeID = {
078    //                                             0x49, 0x50, 0x52, 0x54, 0x45,
079    //                                             0x51, 0x44, 0x57, 0x41, 0x43,
080    //                                             0x4D, 0x3F
081    //                                           };
082
083    ArrayList<JCheckBox> packetChkBoxes = new ArrayList<>();
084    String packetChkBoxLabels[] = {
085                                   "(I) Initialize    ",
086                                   "(P) Poll          ",
087                                   "(R) Read          ",
088                                   "(T) Transmit      ",
089                                   "(E) EOT           ",
090                                   "(Q) Query         ",
091                                   "(D) Datagram Read ",
092                                   "(W) Datagram Write",
093                                   "(A) Datagram Ack  ",
094                                   "(C) Code Line     ",
095                                   "(M) NMRA Mast     ",
096                                   "RFE               "
097                                  };
098
099    protected JPanel packetTypes  = new JPanel();
100
101    HandlerClass packetTypeCkBoxHandler = new HandlerClass();
102    private CMRISystemConnectionMemo _memo = null;
103
104    public SerialFilterFrame(CMRISystemConnectionMemo memo) {
105        super("CMRInet Packet Filter");
106        _memo = memo;
107    }
108
109    /**
110     * {@inheritDoc}
111     */
112    @Override
113    public void initComponents() {
114        initializeNodes();
115
116        // For the class
117        setLayout(new FlowLayout(FlowLayout.LEFT));
118        setPreferredSize(new Dimension(620,375));
119        // setBackground(Color.LIGHT_GRAY);
120
121        // Set up the node filter enable table
122        //------------------------------------
123        nodeEnablePanel = new JPanel();
124        nodeEnablePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
125
126        nodeEnablePanel.setLayout(new BoxLayout(nodeEnablePanel, BoxLayout.LINE_AXIS));
127        nodeEnablePanel.setBorder(nodeEableBorderTitled);
128        nodeEnablePanel.setBackground(Color.WHITE);
129
130        nodeTableModel = new NodeTableModel();
131        nodeTable = new JTable(nodeTableModel);
132
133        nodeTable.setPreferredScrollableViewportSize(new Dimension(200,90));
134        nodeTable.setFillsViewportHeight(true);
135        nodeTable.setShowGrid(true);
136        nodeTable.setGridColor(Color.WHITE);
137        nodeTable.setBackground(Color.WHITE);
138        nodeTable.setRowSelectionAllowed(false);
139        nodeTable.setFont(new Font("Lucida Grande", Font.PLAIN, 13));
140        nodeTable.setRowHeight(30);
141        nodeTable.getTableHeader().setReorderingAllowed(false);
142
143        // Monitor node enable selection check boxes
144        //------------------------------------------
145        JScrollPane nodeTableScrollPane = new JScrollPane(nodeTable);
146        nodeEnablePanel.add(nodeTableScrollPane,BorderLayout.LINE_START);
147
148        nodeEnablePanel.setBorder(nodeEableBorderTitled);
149
150        TableColumnModel nodeEableColumnModel = nodeTable.getColumnModel();
151
152        DefaultTableCellRenderer dtcen = new DefaultTableCellRenderer();
153        dtcen.setHorizontalAlignment(SwingConstants.CENTER);
154        DefaultTableCellRenderer dtlft = new DefaultTableCellRenderer();
155        dtlft.setHorizontalAlignment(SwingConstants.LEFT);
156        TableCellRenderer rendererFromHeader = nodeTable.getTableHeader().getDefaultRenderer();
157        JLabel headerLabel = (JLabel) rendererFromHeader;
158        headerLabel.setHorizontalAlignment(JLabel.CENTER);
159
160        TableColumn nodeaddrColumn = nodeEableColumnModel.getColumn(NodeTableModel.NODEADDR_COLUMN);
161        nodeaddrColumn.setCellRenderer(dtcen);
162        nodeaddrColumn.setResizable(false);
163
164        TableColumn enabledColumn = nodeEableColumnModel.getColumn(NodeTableModel.ENABLED_COLUMN);
165        enabledColumn.setResizable(false);
166
167        nodeEnablePanel.setBorder(nodeEableBorderTitled);
168        nodeEnablePanel.setBackground(Color.WHITE);
169        nodeEnablePanel.setPreferredSize(new Dimension(200,200));
170
171        nodeTable.setAutoCreateRowSorter(true);
172        nodeTable.getRowSorter().toggleSortOrder(NodeTableModel.NODEADDR_COLUMN);
173        nodeEnablePanel.setVisible(true);
174
175        add(nodeEnablePanel);
176
177        // packet type selection check boxes
178        //----------------------------------
179        JPanel packetSelectTypes = new JPanel();
180        packetSelectTypes.setLayout(new GridLayout(0,2));
181        packetSelectTypes.setPreferredSize(new Dimension(400, 200));
182        packetSelectTypes.setBorder(packetTypesBorderTitled);
183        packetSelectTypes.setBackground(Color.WHITE);
184
185        // Losd the packet types filter check boxes
186        //-----------------------------------------
187        for (int i=0; i<numMonPkts; i++)
188        {
189            JCheckBox ckbox = new JCheckBox(packetChkBoxLabels[i]);
190            packetChkBoxes.add(ckbox);
191            packetChkBoxes.get(i).addItemListener(packetTypeCkBoxHandler);
192
193            packetChkBoxes.get(i).setVisible(false);
194            packetChkBoxes.get(i).setEnabled(false);
195            packetChkBoxes.get(i).setSelected(false);
196            if (i<lastStdPkt)
197            {
198                packetChkBoxes.get(i).setVisible(true);
199                packetChkBoxes.get(i).setEnabled(true);
200                packetChkBoxes.get(i).setSelected(true);
201            }
202            packetSelectTypes.add(ckbox);
203        }
204
205        packetSelectTypes.setVisible(true);
206        add(packetSelectTypes);
207
208        // node monitor enable button panel
209        //---------------------------------
210        JPanel enableSelectButtons = new JPanel();
211        enableSelectButtons.setLayout(new FlowLayout(FlowLayout.CENTER));
212        enableSelectButtons.setPreferredSize(new Dimension(200, 60));
213        enableSelectButtons.setBackground(Color.WHITE);
214        enableSelectButtons.setBorder(enabledBorderTitled);
215
216        enableSelectButtons.add(nodeMonitorAll);
217        nodeMonitorAll.setVisible(true);
218        nodeMonitorAll.setToolTipText(Bundle.getMessage("AllButtonTip"));
219        nodeMonitorAll.addActionListener(this::nodeMonitorAllButtonActionPerformed);
220
221        enableSelectButtons.add(nodeMonitorNone);
222        nodeMonitorNone.setVisible(true);
223        nodeMonitorNone.setToolTipText(Bundle.getMessage("NoneButtonTip"));
224        nodeMonitorNone.addActionListener(this::nodeMonitorNoneButtonActionPerformed);
225
226        add(enableSelectButtons);
227
228
229        // packet select enable button panel
230        //----------------------------------
231        JPanel packetSelectButtons = new JPanel();
232        packetSelectButtons.setLayout(new FlowLayout(FlowLayout.LEFT));
233        packetSelectButtons.setPreferredSize(new Dimension(400, 60));
234        packetSelectButtons.setBackground(Color.WHITE);
235        packetSelectButtons.setBorder(packetSelectBorderTitled);
236
237        packetSelectButtons.add(packetMonitorAll);
238        packetMonitorAll.setVisible(true);
239        packetMonitorAll.setToolTipText(Bundle.getMessage("AllButtonTip"));
240        packetMonitorAll.addActionListener(this::packetMonitorAllButtonActionPerformed);
241
242        packetSelectButtons.add(packetMonitorNone);
243        packetMonitorNone.setVisible(true);
244        packetMonitorNone.setToolTipText(Bundle.getMessage("NoneButtonTip") );
245        packetMonitorNone.addActionListener(this::packetMonitorNoneButtonActionPerformed);
246
247        add(packetSelectButtons);
248
249        // Main button panel
250        //------------------
251        JPanel mainButtons = new JPanel();
252        mainButtons.setLayout(new FlowLayout(FlowLayout.RIGHT));
253        mainButtons.setPreferredSize(new Dimension(600, 60));
254
255        haltPollButton.setVisible(true);
256        haltPollButton.setToolTipText(Bundle.getMessage("HaltPollButtonTip"));
257        haltPollButton.addActionListener(this::haltpollButtonActionPerformed);
258        mainButtons.add(haltPollButton);
259
260        mainButtons.add(Box.createRigidArea(new Dimension(30, 0)));
261
262        doneButton.setVisible(true);
263        doneButton.setToolTipText(Bundle.getMessage("DoneButtonTip"));
264        doneButton.addActionListener(this::doneButtonActionPerformed);
265
266        mainButtons.add(doneButton);
267        mainButtons.setVisible(true);
268        add(mainButtons);
269
270        addHelpMenu("package.jmri.jmrix.cmri.serial.serialmon.SerialFilterFrame", true);
271
272        // pack for display
273        //-----------------
274        pack();
275
276    }
277
278    /**
279     * Method to initialize configured nodes and set up the node select combo box
280     */
281    public void initializeNodes() {
282        // get all configured nodes
283        SerialNode node = (SerialNode) _memo.getTrafficController().getNode(0);
284        int index = 1;
285        while (node != null) {
286            monitorNode.add(node);
287            node = (SerialNode) _memo.getTrafficController().getNode(index);
288            index++;
289        }
290    }
291
292    /**
293     * Set MonitorNodePackets.
294     * @param e unused.
295     */
296    public void nodeMonitorAllButtonActionPerformed(ActionEvent e) {
297        for(int i=0; i<monitorNode.size(); i++) {
298            monitorNode.get(i).setMonitorNodePackets(false);
299            nodeTableModel.setValueAt(monitorNode.get(i).getMonitorNodePackets(), i, NodeTableModel.ENABLED_COLUMN);
300        }
301    }
302
303    public void nodeMonitorNoneButtonActionPerformed(ActionEvent e) {
304        for(int i=0; i<monitorNode.size(); i++) {
305            monitorNode.get(i).setMonitorNodePackets(true);
306            nodeTableModel.setValueAt(monitorNode.get(i).getMonitorNodePackets(), i, NodeTableModel.ENABLED_COLUMN);
307        }
308    }
309
310    public void packetMonitorAllButtonActionPerformed(ActionEvent e) {
311        for (int i=0; i<lastStdPkt; i++) {
312            packetChkBoxes.get(i).setSelected(true);
313        }
314    }
315
316    public void packetMonitorNoneButtonActionPerformed(ActionEvent e) {
317        for (int i=0; i<lastStdPkt; i++) {
318            packetChkBoxes.get(i).setSelected(false);
319        }
320    }
321
322    public void doneButtonActionPerformed(ActionEvent e) {
323        setVisible(false);
324        dispose();
325    }
326
327    /* ---------------------------- */
328    /* Halt Poll button handler */
329    /* ---------------------------- */
330    public void haltpollButtonActionPerformed(ActionEvent e) {
331        SerialTrafficController stc = _memo.getTrafficController();
332        stc.setPollNetwork(!stc.getPollNetwork());
333        if (stc.getPollNetwork()) {
334            haltPollButton.setText(Bundle.getMessage("HaltPollingText"));
335        } else {
336            haltPollButton.setText(Bundle.getMessage("StartPollingText"));
337        }
338    }
339
340    // -------------------------------
341    // cpNode options checkbox handler
342    // -------------------------------
343    private class HandlerClass implements ItemListener{
344        @Override
345        public void itemStateChanged(ItemEvent e){
346            JCheckBox pktTypeChkBox = (JCheckBox) e.getSource();
347            int pktTypeIndex = 0;
348            SerialNode aNode;
349            do {
350                if (pktTypeChkBox == packetChkBoxes.get(pktTypeIndex)) {
351                    for (int i=0; i < monitorNode.size(); i++) {
352                        aNode = monitorNode.get(i);
353                        if (aNode != null) {
354                            aNode.setMonitorPacketBit(pktTypeIndex,(packetChkBoxes.get(pktTypeIndex).isSelected()));
355                        }
356                    }
357                    return;
358                }
359                pktTypeIndex++;
360            } while ( pktTypeIndex < numMonPkts);
361        }
362    }
363    /**
364     * Set up table for displaying bit assignments
365     */
366    public class NodeTableModel extends AbstractTableModel {
367        @Override
368        public String getColumnName(int c) {
369            return nodeEnableColumnsNames[c];
370        }
371        @Override
372        public Class<?> getColumnClass(int c) {
373            switch (c) {
374                case NODEADDR_COLUMN:
375                    return Integer.class;
376                default:
377                    return Boolean.class;
378            }
379        }
380
381        @Override
382        public boolean isCellEditable(int r, int c) {
383            return c != NODEADDR_COLUMN;
384        }
385
386        @Override
387        public int getColumnCount() {
388            return NUMCOLUMNS;
389        }
390
391        @Override
392        public int getRowCount() {
393            return monitorNode.size();
394        }
395
396        @Override
397        public Object getValueAt(int r, int c) {
398
399            switch (c) {
400                case NODEADDR_COLUMN:
401                    return monitorNode.get(r).getNodeAddress();
402                case ENABLED_COLUMN:
403                    return monitorNode.get(r).getMonitorNodePackets();
404                default:
405                    return true;
406            }
407        }
408
409        @Override
410        public void setValueAt(Object value, int r, int c) {
411            if (c == NODEADDR_COLUMN) {
412                monitorNode.get(r).setPollListPosition((Integer) value);
413            } else if (c == ENABLED_COLUMN) {
414                monitorNode.get(r).setMonitorNodePackets(!monitorNode.get(r).getMonitorNodePackets());
415            }
416            fireTableDataChanged();
417        }
418
419        public static final int NODEADDR_COLUMN = 0;
420        public static final int ENABLED_COLUMN  = 1;
421        public static final int NUMCOLUMNS = ENABLED_COLUMN+1;
422    }
423
424    private final String[] nodeEnableColumnsNames = {"Node", "Monitor"};
425
426    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SerialFilterFrame.class);
427
428}