ArduinoTableNodeConnect.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 Node Connection Table.
 */
public class ArduinoTableNodeConnect {
    /**
     * Half Weight.
     */
    static final double HALF_WEIGHT = 0.5;

    /**
     * Third Weight.
     */
    static final double THIRD_WEIGHT = 0.33;

    /**
     * The splitPane.
     */
    private final JSplitPane thePane;

    /**
     * The sent model.
     */
    private final ArduinoSentModel theSentModel;

    /**
     * The received table.
     */
    private final JTable theReceivedTable;

    /**
     * The received model.
     */
    private final ArduinoReceivedModel theReceivedModel;

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

    /**
     * The selected node.
     */
    private ArduinoNode theSelected;

    /**
     * Constructor.
     */
    ArduinoTableNodeConnect() {
        /* Create the tables */
        final JTable mySentTable = new JTable();
        mySentTable.setAutoCreateRowSorter(true);
        theReceivedTable = new JTable();
        theReceivedTable.setAutoCreateRowSorter(true);
        theReceivedTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        final JTable mySignalsTable = new JTable();
        mySignalsTable.setAutoCreateRowSorter(true);

        /* Create the table models */
        theSentModel = new ArduinoSentModel();
        mySentTable.setModel(theSentModel);
        theReceivedModel = new ArduinoReceivedModel();
        theReceivedTable.setModel(theReceivedModel);
        theSignalsModel = new ArduinoSignalsModel();
        mySignalsTable.setModel(theSignalsModel);

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

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

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

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

    /**
     * Configure the table.
     *
     * @param pNode the node
     */
    void configureTable(final ArduinoNode pNode) {
        /* refresh the tables */
        theSelected = pNode;
        theReceivedModel.refresh(pNode);
        theSentModel.refresh(pNode);
    }

    /**
     * Sent Messages Table Model.
     */
    private static class ArduinoSentModel
            extends AbstractTableModel {
        /**
         * Serial Id.
         */
        private static final long serialVersionUID = -3464529356295378185L;

        /**
         * The message column.
         */
        private static final int COL_MSG = 0;

        /**
         * The active Messages list.
         */
        private final List<ArduinoMessage> theMessages;

        /**
         * Constructor.
         */
        ArduinoSentModel() {
            theMessages = new ArrayList<>();
        }

        /**
         * Refresh.
         * @param pNode the node
         */
        void refresh(final ArduinoNode pNode) {
            /* Clear the messages */
            theMessages.clear();

            /* If we have a node */
            if (pNode != null) {
                /* Loop through the messages */
                for (ArduinoMessage myMsg : pNode.getOwner().getMessages()) {
                    if (pNode.sendsMessage(myMsg)) {
                        theMessages.add(myMsg);
                    }
                }
            }

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

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

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

        @Override
        public int getColumnCount() {
            return COL_MSG + 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_MSG ? theMessages.get(pRowIndex).getName() : null;
        }
    }

    /**
     * Received Messages Table Model.
     */
    private class ArduinoReceivedModel
            extends AbstractTableModel {
        /**
         * Serial Id.
         */
        private static final long serialVersionUID = 1102886271097401423L;

        /**
         * The message column.
         */
        private static final int COL_MSG = 0;

        /**
         * The active Messages list.
         */
        private final List<ArduinoMessage> theMessages;

        /**
         * Constructor.
         */
        ArduinoReceivedModel() {
            theMessages = new ArrayList<>();
        }

        /**
         * Refresh.
         * @param pNode the node
         */
        void refresh(final ArduinoNode pNode) {
            /* Clear the messages */
            theMessages.clear();

            /* If we have a node */
            if (pNode != null) {
                /* Loop through the messages */
                for (ArduinoMessage myMsg : pNode.getOwner().getMessages()) {
                    if (pNode.receivesMessage(myMsg)) {
                        theMessages.add(myMsg);
                    }
                }
            }

            /* Refresh the table */
            fireTableDataChanged();

            /* Select the first message if available */
            if (!theMessages.isEmpty()) {
                theReceivedTable.changeSelection(0, 0, false, false);

                /* else clear the signals */
            } else {
                theSignalsModel.refresh(null, null);
            }
        }

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

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

        @Override
        public int getColumnCount() {
            return COL_MSG + 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_MSG ? theMessages.get(pRowIndex).getName() : null;
        }

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

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

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

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

        /**
         * Constructor.
         */
        ArduinoSignalsModel() {
            theSignals = new ArrayList<>();
        }

        /**
         * Refresh.
         * @param pNode the node
         * @param pMessage the message
         */
        void refresh(final ArduinoNode pNode,
                     final ArduinoMessage pMessage) {
            /* Clear the signals */
            theSignals.clear();

            /* If we have a message */
            if (pMessage != null) {
                /* Loop through the signals */
                for (ArduinoSignal mySignal : pMessage.getAllSignals()) {
                    /* Add signal if it is received by the node */
                    if (mySignal.getReceivers().contains(pNode)) {
                        theSignals.add(mySignal);
                    }
                }
            }

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

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

        @Override
        public String getColumnName(final int pColIndex) {
            return pColIndex == COL_SIGNAL ? "Received Signals" :  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;
        }
    }
}