All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.mvc.debug.view.DebugInterfaceView Maven / Gradle / Ivy

There is a newer version: 2.0.0-M1
Show newest version
package org.bidib.wizard.mvc.debug.view;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.BadLocationException;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.SystemUtils;
import org.bidib.jbidibc.serial.exception.InvalidLibraryException;
import org.bidib.jbidibc.serial.util.PortIdentifierUtils;
import org.bidib.wizard.dialog.FileDialog;
import org.bidib.wizard.locale.Resources;
import org.bidib.wizard.mvc.common.model.CommPort;
import org.bidib.wizard.mvc.common.view.DockKeys;
import org.bidib.wizard.mvc.debug.controller.listener.DebugInterfaceControllerListener;
import org.bidib.wizard.mvc.debug.model.DebugInterfaceModel;
import org.bidib.wizard.mvc.debug.view.listener.DebugInterfaceViewListener;
import org.bidib.wizard.mvc.main.view.menu.BasicPopupMenu;
import org.jdesktop.swingx.prompt.PromptSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.adapter.ComboBoxAdapter;
import com.jgoodies.binding.beans.PropertyAdapter;
import com.jgoodies.binding.beans.PropertyConnector;
import com.jgoodies.binding.list.SelectionInList;
import com.jgoodies.binding.value.ConverterValueModel;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.debug.FormDebugPanel;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.FormLayout;
import com.vlsolutions.swing.docking.DockKey;
import com.vlsolutions.swing.docking.Dockable;
import com.vlsolutions.swing.docking.DockableState;
import com.vlsolutions.swing.docking.DockingDesktop;
import com.vlsolutions.swing.docking.event.DockableStateChangeEvent;
import com.vlsolutions.swing.docking.event.DockableStateChangeListener;

public class DebugInterfaceView implements Dockable {
    private static final Logger LOGGER = LoggerFactory.getLogger(DebugInterfaceView.class);

    private static final String ENCODED_DIALOG_COLUMN_SPECS =
        "pref, 3dlu, 50dlu, 3dlu, pref, 3dlu, pref, 3dlu, fill:pref:grow, 3dlu, pref, 3dlu, pref";

    private final Collection listeners = new LinkedList<>();

    private final DebugInterfaceModel debugInterfaceModel;

    private final DockableStateChangeListener dockableStateChangeListener;

    private final JPanel contentPanel;

    private ValueModel selectionHolderComPort;

    private ValueModel sendTextValueModel;

    private ValueModel selectionHolderBaudRate;

    private ValueModel sendFileValueModel;

    private JTextField sendText;

    private JTextField sendFile;

    private final JButton connectButton = new JButton(Resources.getString(getClass(), "connect"));

    private final JButton disconnectButton = new JButton(Resources.getString(getClass(), "disconnect"));

    private final JButton transmitButton = new JButton(Resources.getString(getClass(), "transmit"));

    private final JButton transmitFileButton = new JButton(Resources.getString(getClass(), "transmit"));

    private final JButton selectFileButton = new JButton(Resources.getString(getClass(), "selectFile"));

    private final JTextArea logsArea = new JTextArea();

    private SelectionInList commPortSelection;

    public DebugInterfaceView(final DockingDesktop desktop, final DebugInterfaceControllerListener listener,
        final DebugInterfaceModel debugInterfaceModel) {

        DockKeys.DOCKKEY_DEBUG_INTERFACE_VIEW.setName(Resources.getString(getClass(), "title"));
        DockKeys.DOCKKEY_DEBUG_INTERFACE_VIEW.setFloatEnabled(true);
        DockKeys.DOCKKEY_DEBUG_INTERFACE_VIEW.setAutoHideEnabled(false);

        dockableStateChangeListener = new DockableStateChangeListener() {

            @Override
            public void dockableStateChanged(DockableStateChangeEvent event) {
                LOGGER.info("The state has changed, newState: {}, prevState: {}", event.getNewState(),
                    event.getPreviousState());

                DockableState newState = event.getNewState();
                if (newState.getDockable().equals(DebugInterfaceView.this) && newState.isClosed()) {
                    LOGGER.info("The DebugInterfaceView is closed.");
                    // we are closed
                    desktop.removeDockableStateChangeListener(dockableStateChangeListener);

                    if (listener != null) {
                        LOGGER.info("Close the view.");

                        listener.viewClosed();
                    }
                }

            }
        };
        desktop.addDockableStateChangeListener(dockableStateChangeListener);

        LOGGER.info("Create new DebugInterfaceView");
        this.debugInterfaceModel = debugInterfaceModel;

        loadPortIdentifiers(debugInterfaceModel);

        // create form builder
        DefaultFormBuilder dialogBuilder = null;
        boolean debugDialog = false;
        if (debugDialog) {
            JPanel panel = new FormDebugPanel();
            dialogBuilder = new DefaultFormBuilder(new FormLayout(ENCODED_DIALOG_COLUMN_SPECS), panel);
        }
        else {
            JPanel panel = new JPanel(new BorderLayout());
            dialogBuilder = new DefaultFormBuilder(new FormLayout(ENCODED_DIALOG_COLUMN_SPECS), panel);
        }
        dialogBuilder.border(Borders.DIALOG);

        // add some components
        commPortSelection =
            new SelectionInList((ListModel) debugInterfaceModel.getCommPortsListModel());

        selectionHolderComPort =
            new PropertyAdapter(debugInterfaceModel, DebugInterfaceModel.PROPERTY_SELECTED_PORT,
                true);

        ComboBoxAdapter comboBoxAdapterCommPorts =
            new ComboBoxAdapter(commPortSelection, selectionHolderComPort);
        JComboBox comboCommPorts = new JComboBox();
        comboCommPorts.setModel(comboBoxAdapterCommPorts);

        dialogBuilder.append(Resources.getString(getClass(), "selectedPort"), comboCommPorts);

        List baudRates = new ArrayList<>();
        baudRates.add(Integer.valueOf(19200));
        baudRates.add(Integer.valueOf(115200));
        selectionHolderBaudRate =
            new PropertyAdapter(debugInterfaceModel, DebugInterfaceModel.PROPERTY_BAUDRATE, true);
        ComboBoxAdapter comboBoxAdapter = new ComboBoxAdapter(baudRates, selectionHolderBaudRate);

        JComboBox comboBaudRate = new JComboBox<>();
        comboBaudRate.setModel(comboBoxAdapter);
        comboBaudRate.setSelectedIndex(1);

        dialogBuilder.append(Resources.getString(getClass(), "selectedBaudRate"), comboBaudRate);

        connectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireConnect();
            }
        });
        disconnectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireDisconnect();
            }
        });
        disconnectButton.setEnabled(false);

        // prepare the connect and disconnect button
        JPanel debugInterfaceActionButtons =
            new ButtonBarBuilder().addButton(connectButton).addRelatedGap().addButton(disconnectButton).build();
        dialogBuilder.append(debugInterfaceActionButtons);

        dialogBuilder.appendRow("3dlu");
        dialogBuilder.appendRow("fill:200dlu:grow");
        dialogBuilder.nextLine(2);

        logsArea.setEditable(false);
        logsArea.setFont(new Font("Monospaced", Font.PLAIN, 11));

        JScrollPane logsPane = new JScrollPane(logsArea);

        logsPane.setAutoscrolls(true);
        dialogBuilder.append(logsPane, 13);

        dialogBuilder.appendRow("3dlu");
        dialogBuilder.appendRow("pref");
        dialogBuilder.nextLine(2);

        // create the textfield for send message to debug
        sendTextValueModel =
            new PropertyAdapter(debugInterfaceModel, DebugInterfaceModel.PROPERTY_SEND_TEXT, true);
        sendText = BasicComponentFactory.createTextField(sendTextValueModel, false);
        sendText.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireTransmit();
            }
        });

        PromptSupport.init(Resources.getString(getClass(), "transmitText.prompt"), null, null, sendText);
        dialogBuilder.append(Resources.getString(getClass(), "transmitText"), sendText, 9);

        dialogBuilder.append(transmitButton);
        transmitButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireTransmit();
            }
        });
        transmitButton.setEnabled(false);

        dialogBuilder.appendRow("3dlu");
        dialogBuilder.appendRow("pref");
        dialogBuilder.nextLine(2);

        // create the textfield for filename
        sendFileValueModel =
            new PropertyAdapter(debugInterfaceModel, DebugInterfaceModel.PROPERTY_SEND_FILE, true);
        final ValueModel sendFileConverterModel =
            new ConverterValueModel(sendFileValueModel, new FileStringConverter());
        sendFile = BasicComponentFactory.createTextField(sendFileConverterModel, true);
        sendFile.setEditable(false);
        PromptSupport.init(Resources.getString(getClass(), "transmitFile.prompt"), null, null, sendFile);
        dialogBuilder.append(Resources.getString(getClass(), "transmitFile"), sendFile, 7);

        dialogBuilder.append(selectFileButton);
        selectFileButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireSelectFile();
            }
        });

        dialogBuilder.append(transmitFileButton);
        transmitFileButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fireTransmitFile();
            }
        });
        transmitFileButton.setEnabled(false);

        // add bindings for enable/disable the send button
        PropertyConnector.connect(debugInterfaceModel, DebugInterfaceModel.PROPERTY_TRANSMIT_ENABLED, transmitButton,
            "enabled");
        PropertyConnector.connect(debugInterfaceModel, DebugInterfaceModel.PROPERTY_TRANSMIT_ENABLED,
            transmitFileButton, "enabled");

        PropertyConnector.connect(debugInterfaceModel, DebugInterfaceModel.PROPERTY_DISCONNECTED, connectButton,
            "enabled");
        PropertyConnector.connect(debugInterfaceModel, DebugInterfaceModel.PROPERTY_CONNECTED, disconnectButton,
            "enabled");

        contentPanel = dialogBuilder.build();

        JPopupMenu popupMenu = new BasicPopupMenu();
        JMenuItem clearConsole = new JMenuItem(Resources.getString(getClass(), "clear_console"));
        clearConsole.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                fireClearConsole();
            }
        });
        popupMenu.add(clearConsole);
        logsArea.setComponentPopupMenu(popupMenu);
    }

    private void fireClearConsole() {
        LOGGER.info("clear the console.");

        logsArea.setText(null);
    }

    private void fireConnect() {
        for (DebugInterfaceViewListener listener : listeners) {
            listener.openConnection();
        }
    }

    private void fireDisconnect() {
        for (DebugInterfaceViewListener listener : listeners) {
            listener.closeConnection();
        }
    }

    private void fireTransmit() {

        for (DebugInterfaceViewListener listener : listeners) {
            listener.transmit();
        }
        // clear the text field
        sendText.setText(null);
    }

    private void fireTransmitFile() {

        boolean modal = true;

        FileTransferProgressDialog progressDialog = new FileTransferProgressDialog(contentPanel, modal, listeners);

    }

    private void fireSelectFile() {
        final FileDialog dialog = new FileDialog(
            contentPanel, FileDialog.OPEN, null, ff) {
            @Override
            public void approve(String selectedFile) {
                File file = new File(selectedFile);

                selectedFile = file.getName();

                // debugInterfaceModel.setSendFile(null);

                debugInterfaceModel.setSendFile(file);
            }
        };
        dialog.showDialog();
    }

    @Override
    public DockKey getDockKey() {
        return DockKeys.DOCKKEY_DEBUG_INTERFACE_VIEW;
    }

    @Override
    public Component getComponent() {
        return contentPanel;
    }

    public void addDebugInterfaceViewListener(DebugInterfaceViewListener l) {
        listeners.add(l);
    }

    private int currentLineLen;

    public void addLog(final String logMessage) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    int lines = logsArea.getLineCount();
                    if (lines > 500) {
                        // remove the first 50 lines
                        int end = logsArea.getLineEndOffset(/* lines - */50);
                        logsArea.getDocument().remove(0, end);
                    }
                }
                catch (BadLocationException ex) {
                    LOGGER.warn("Remove some lines from logsArea failed.", ex);
                }

                int index = logMessage.lastIndexOf("\n");
                if (index > 0) {
                    // check if we have text that is following the line break
                    if ((logMessage.length() - 1) > index) {

                        currentLineLen += (logMessage.length() - 1) - index;
                    }
                }
                else {
                    currentLineLen += logMessage.length();
                }

                // Update and scroll pane to the bottom
                logsArea.append(logMessage);

                if (currentLineLen > 120) {
                    // break the line
                    logsArea.append(SystemUtils.LINE_SEPARATOR);
                    currentLineLen = 0;
                }
                logsArea.invalidate();
            }
        });
    }

    private static final String SUFFIX_HEX = "hex";

    private static final String SUFFIX_EEP = "eep";

    private final FileFilter ff = new FileFilter() {

        @Override
        public boolean accept(File file) {
            boolean result = false;

            if (file != null) {
                if (file.isDirectory()) {
                    result = true;
                }
                else if (FilenameUtils.wildcardMatch(file.getName(), "*." + SUFFIX_HEX)) {
                    result = true;
                }
                else if (FilenameUtils.wildcardMatch(file.getName(), "*." + SUFFIX_EEP)) {
                    result = true;
                }
            }
            return result;
        }

        @Override
        public String getDescription() {
            return Resources.getString(DebugInterfaceView.class, "filter") + " (*." + SUFFIX_HEX + ",*." + SUFFIX_EEP
                + ")";
        }
    };

    private void loadPortIdentifiers(DebugInterfaceModel model) {
        LOGGER.info("Load the comm ports, model: {}", model);
        Set commPorts = new HashSet();

        try {
            // use PortIdentifierUtils because we must load the RXTX libraries
            List portIdentifiers = PortIdentifierUtils.getPortIdentifiers();

            if (portIdentifiers != null) {
                for (String id : portIdentifiers) {
                    LOGGER.info("Add new CommPort with id: {}", id);
                    commPorts.add(new CommPort(id));
                }
            }
        }
        catch (InvalidLibraryException ex) {
            LOGGER
                .warn(
                    "Fetch port identifiers failed. This can be caused because the ext/lib directory of the Java installation contains an old RXTXComm.jar!",
                    ex);

            JOptionPane.showMessageDialog(contentPanel, Resources.getString(DebugInterfaceView.class,
                "fetch-port-identifiers-failed",
                new Object[] { new File(SystemUtils.getJavaHome(), "lib/ext").getPath() }), Resources.getString(
                DebugInterfaceView.class, "title-error"), JOptionPane.ERROR_MESSAGE);
        }
        catch (Exception ex) {
            LOGGER.warn("Fetch port identifiers failed.", ex);
        }
        model.setCommPorts(Arrays.asList(commPorts.toArray(new CommPort[0])));

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy