ArduinoTableMsgConnect.java

/*******************************************************************************
 * jArduino: Arduino C++ Code Generation From Java
 * Copyright 2020 Tony Washer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package net.sourceforge.jarduino.gui;

import net.sourceforge.jarduino.message.ArduinoMessage;
import net.sourceforge.jarduino.message.ArduinoNode;
import net.sourceforge.jarduino.message.ArduinoSignal;

import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.List;

/**
 * Arduino Message Connection Table.
 */
public class ArduinoTableMsgConnect {
    /**
     * The splitPane.
     */
    private final JSplitPane thePane;

    /**
     * The signals table.
     */
    private final JTable theSignalsTable;

    /**
     * The signals model.
     */
    private final ArduinoSignalsModel theSignalsModel;

    /**
     * The signals nodes model.
     */
    private final ArduinoSignalNodesModel theNodesModel;

    /**
     * The senders model.
     */
    private final ArduinoSentByModel theSendersModel;

    /**
     * Constructor.
     */
    ArduinoTableMsgConnect() {
        /* Create the tables */
        theSignalsTable = new JTable();
        theSignalsTable.setAutoCreateRowSorter(true);
        theSignalsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        final JTable mySignalNodesTable = new JTable();
        mySignalNodesTable.setAutoCreateRowSorter(true);
        final JTable mySendingNodesTable = new JTable();
        mySendingNodesTable.setAutoCreateRowSorter(true);

        /* Create the table models */
        theSignalsModel = new ArduinoSignalsModel();
        theSignalsTable.setModel(theSignalsModel);
        theNodesModel = new ArduinoSignalNodesModel();
        mySignalNodesTable.setModel(theNodesModel);
        theSendersModel = new ArduinoSentByModel();
        mySendingNodesTable.setModel(theSendersModel);

        /* Create a splitPane */
        final JSplitPane myPane =  new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        myPane.setLeftComponent(new JScrollPane(theSignalsTable));
        myPane.setRightComponent(new JScrollPane(mySignalNodesTable));
        myPane.setResizeWeight(ArduinoTableNodeConnect.HALF_WEIGHT);

        /* Update nodes on selection of signal */
        final ListSelectionModel mySelect = theSignalsTable.getSelectionModel();
        mySelect.addListSelectionListener(e -> {
            if (!e.getValueIsAdjusting()) {
                int myIndex = mySelect.getMinSelectionIndex();
                if (myIndex != -1) {
                    myIndex = theSignalsTable.convertRowIndexToModel(myIndex);
                    theNodesModel.refresh(theSignalsModel.getItem(myIndex));
                }
            }
        });

        /* Create a splitPane */
        thePane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        thePane.setLeftComponent(new JScrollPane(mySendingNodesTable));
        thePane.setRightComponent(myPane);
        thePane.setResizeWeight(ArduinoTableNodeConnect.THIRD_WEIGHT);
    }

    /**
     * Obtain the component.
     * @return the component
     */
    JComponent getComponent() {
        return thePane;
    }

    /**
     * Configure the table.
     *
     * @param pMessage the message
     */
    void configureTable(final ArduinoMessage pMessage) {
        /* refresh the tables */
        theSignalsModel.refresh(pMessage);
        theSendersModel.refresh(pMessage);
    }

    /**
     * Sending Nodes Table Model.
     */
    private static class ArduinoSentByModel
            extends AbstractTableModel {
        /**
         * Serial Id.
         */
        private static final long serialVersionUID = 5860442671388666448L;

        /**
         * The sender column.
         */
        private static final int COL_SENDER = 0;

        /**
         * The active Nodes list.
         */
        private final List<ArduinoNode> theSenders;

        /**
         * Constructor.
         */
        ArduinoSentByModel() {
            theSenders = new ArrayList<>();
        }

        /**
         * Refresh.
         * @param pMessage the message
         */
        void refresh(final ArduinoMessage pMessage) {
            /* Clear the messages */
            theSenders.clear();

            /* If we have a node */
            if (pMessage != null) {
                /* Loop through the messages */
                for (ArduinoNode myNode : pMessage.getSystem().getNodes()) {
                    /* Add if this is not the Null node and it sends the message */
                    if (!ArduinoNode.NULL_NODE.equals(myNode.getName())
                        && myNode.sendsMessage(pMessage)) {
                        theSenders.add(myNode);
                    }
                }
            }

            /* Refresh the table */
            fireTableDataChanged();
        }

        @Override
        public int getRowCount() {
            return theSenders.size();
        }

        @Override
        public String getColumnName(final int pColIndex) {
            return pColIndex == COL_SENDER ? "Sent By" :  null;
        }

        @Override
        public int getColumnCount() {
            return COL_SENDER + 1;
        }

        @Override
        public boolean isCellEditable(final int pRowIndex,
                                      final int pColIndex) {
            return false;
        }

        @Override
        public Object getValueAt(final int pRowIndex,
                                 final int pColIndex) {
            return pColIndex == COL_SENDER ? theSenders.get(pRowIndex).getName() : null;
        }
    }

    /**
     * Signals Table Model.
     */
    private class ArduinoSignalsModel
            extends AbstractTableModel {
        /**
         * Serial Id.
         */
        private static final long serialVersionUID = 3438477307113875891L;

        /**
         * The signal column.
         */
        private static final int COL_SIGNAL = 0;

        /**
         * The active Signals list.
         */
        private List<ArduinoSignal> theSignals;

        /**
         * Constructor.
         */
        ArduinoSignalsModel() {
        }

        /**
         * Refresh.
         * @param pMessage the message
         */
        void refresh(final ArduinoMessage pMessage) {
            /* Record the nodes */
            theSignals = pMessage == null ? null : pMessage.getAllSignals();

            /* Refresh the table */
            fireTableDataChanged();

            /* Select the first message if available */
            if (theSignals != null && !theSignals.isEmpty()) {
                theSignalsTable.changeSelection(0, 0, false, false);

                /* else clear the nodes */
            } else {
                theNodesModel.refresh(null);
            }
        }

        @Override
        public int getRowCount() {
            return theSignals == null ? 0 : theSignals.size();
        }

        @Override
        public String getColumnName(final int pColIndex) {
            return pColIndex == COL_SIGNAL ? "Signal" :  null;
        }

        @Override
        public int getColumnCount() {
            return COL_SIGNAL + 1;
        }

        @Override
        public boolean isCellEditable(final int pRowIndex,
                                      final int pColIndex) {
            return false;
        }

        @Override
        public Object getValueAt(final int pRowIndex,
                                 final int pColIndex) {
            return pColIndex == COL_SIGNAL ? theSignals.get(pRowIndex).getName() : null;
        }

        /**
         * Obtain the item at index.
         * @param pIndex the index
         * @return the item
         */
        ArduinoSignal getItem(final int pIndex) {
            return theSignals.get(pIndex);
        }
    }

    /**
     * Signal Nodes Table Model.
     */
    private static class ArduinoSignalNodesModel
            extends AbstractTableModel {
        /**
         * Serial Id.
         */
        private static final long serialVersionUID = 2945394153649721652L;

        /**
         * The node column.
         */
        private static final int COL_NODE = 0;

        /**
         * The active Nodes list.
         */
        private final List<ArduinoNode> theNodes;

        /**
         * Constructor.
         */
        ArduinoSignalNodesModel() {
            theNodes = new ArrayList<>();
        }

        /**
         * Refresh.
         * @param pSignal the signal
         */
        void refresh(final ArduinoSignal pSignal) {
            /* Clear the list */
            theNodes.clear();

            /* If we have a signal */
            if (pSignal != null) {
                /* Loop through the receivers */
                for (ArduinoNode myNode : pSignal.getReceivers()) {
                    /* Add if this is not the Null node */
                    if (!ArduinoNode.NULL_NODE.equals(myNode.getName())) {
                        theNodes.add(myNode);
                    }
                }
            }

            /* Refresh the table */
            fireTableDataChanged();
        }

        @Override
        public int getRowCount() {
            return theNodes.size();
        }

        @Override
        public String getColumnName(final int pColIndex) {
            return pColIndex == COL_NODE ? "Received By" :  null;
        }

        @Override
        public int getColumnCount() {
            return COL_NODE + 1;
        }

        @Override
        public boolean isCellEditable(final int pRowIndex,
                                      final int pColIndex) {
            return false;
        }

        @Override
        public Object getValueAt(final int pRowIndex,
                                 final int pColIndex) {
            return pColIndex == COL_NODE ? theNodes.get(pRowIndex).getName() : null;
        }
    }
}