ArduinoPanelMain.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 java.awt.BorderLayout;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import net.sourceforge.jarduino.ArduinoException;
import net.sourceforge.jarduino.util.ArduinoLogManager;
import net.sourceforge.jarduino.util.ArduinoLogger;

/**
 * Arduino Swing StartUp.
 */
public final class ArduinoPanelMain {
    /**
     * The LOGGER.
     */
    private static final ArduinoLogger LOGGER = ArduinoLogManager.getLogger(ArduinoPanelMain.class);

    /**
     * The Default Width.
     */
    static final int WIDTH = 900;

    /**
     * The Default Height.
     */
    static final int HEIGHT = 400;

    /**
     * The StrutSize.
     */
    static final int STRUTSIZE = 5;

    /**
     * The Frame.
     */
    private final JFrame theFrame;

    /**
     * The tabPane.
     */
    private final JTabbedPane theTabs;

   /**
     * The sourcePane.
     */
    private final ArduinoPanelSource theSource;

    /**
     * The messagePane.
     */
    private final ArduinoPanelSignal theMessage;

    /**
     * The metaDataPane.
     */
    private final ArduinoPanelMeta theMeta;

    /**
     * The error panel.
     */
    private final JPanel theErrorPanel;

    /**
     * The error Label.
     */
    private final JLabel theErrorLabel;

    /**
     * The detail label.
     */
    private final JLabel theDetail;

    /**
     * The error.
     */
    private ArduinoException theError;

    /**
     * Constructor.
     * @throws ArduinoException on error
     */
    ArduinoPanelMain() throws ArduinoException {
        /* Create the frame */
        theFrame = new JFrame();
        theFrame.setTitle("jArduino");

        /* Build the tabs */
        theTabs = new JTabbedPane();

        /* Create the panels that exist for a loaded file */
        theSource = new ArduinoPanelSource(theFrame);
        theMessage = new ArduinoPanelSignal(theFrame);
        theMeta = new ArduinoPanelMeta(theFrame);

        /* Create the error detail and clear button */
        theDetail = new JLabel();
        final JButton myClear = new JButton();
        myClear.setText("Clear");
        myClear.addActionListener(e -> clearError());

        /* Create the base error panel */
        theErrorLabel = new JLabel();
        final JPanel myErrorPanel = new JPanel();
        myErrorPanel.setLayout(new BoxLayout(myErrorPanel, BoxLayout.X_AXIS));
        myErrorPanel.add(theErrorLabel);
        myErrorPanel.add(Box.createHorizontalGlue());
        myErrorPanel.add(myClear);

        /* Create the error panel */
        theErrorPanel = new JPanel();
        theErrorPanel.setLayout(new BoxLayout(theErrorPanel, BoxLayout.Y_AXIS));
        theErrorPanel.add(myErrorPanel);
        theErrorPanel.add(theDetail);
        theErrorPanel.setVisible(false);

        /* Build the frame */
        buildFrame();
    }

    /**
     * Obtain the frame.
     * @return the frame
     */
    JFrame getFrame() {
        return theFrame;
    }

    /**
     * Build the frame.
     * @throws ArduinoException on error
     */
    private void buildFrame() throws ArduinoException {
        /* Create a borderLayout */
        final JPanel myPanel = new JPanel();
        myPanel.setLayout(new BorderLayout());
        myPanel.add(theErrorPanel, BorderLayout.PAGE_START);
        myPanel.add(theTabs, BorderLayout.CENTER);

        /* Attach the panel to the frame */
        theFrame.setContentPane(myPanel);
        theFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        theFrame.addWindowListener(new WindowClose());

        /* Load icon */
        theFrame.setIconImage(loadImage());

        /* Create menuBar */
        final ArduinoMenuBar myMenuBar = new ArduinoMenuBar(theFrame, this);
        theFrame.setJMenuBar(myMenuBar.getComponent());

        /* Show the frame */
        theFrame.pack();
        theFrame.setLocationRelativeTo(null);
        theFrame.setVisible(true);
    }

    /**
     * Load image.
     * @return the icon
     * @throws ArduinoException on error
     */
    private static Image loadImage() throws ArduinoException {
        /* Protect against exceptions */
        try (InputStream myStream = ArduinoPanelMain.class.getResourceAsStream("icons/BlueJellyGears.png")) {
            return ImageIO.read(myStream);

            /* Handle exceptions */
        } catch (IOException e) {
            throw new ArduinoException("Failed to load icon", e);
        }
    }

    /**
     * Set the selected system.
     * @param pSelected the selected system.
     * @param pCharSet the character set to use
     * @return the error or null for success
     */
    ArduinoException setSelected(final File pSelected,
                                 final Charset pCharSet) {
        /* Process the selected file */
        final boolean bSuccess = theSource.setSelected(pSelected, pCharSet);

        /* If we were successful */
        if (bSuccess) {
            /* Remove the source component */
            theTabs.remove(theSource.getComponent());
            theTabs.remove(theMessage.getComponent());
            theTabs.remove(theMeta.getComponent());

            /* Insert tab if we were successful */
            theFrame.setTitle("jArduino - " + theSource.getSystem().getName());
            theTabs.insertTab("MetaData", null, theMeta.getComponent(), null, 0);
            theMeta.setSystem(theSource.getSystem());
            theTabs.insertTab("Message", null, theMessage.getComponent(), null, 0);
            theMessage.setSystem(theSource.getSystem());
            theTabs.insertTab("Sources", null, theSource.getComponent(), null, 0);
            theTabs.setSelectedIndex(0);

            /* return success indication */
            return null;

            /* else report the error */
        } else {
            return theSource.getError();
        }
    }

    /**
     * Write the sketch output.
     * @param pOutDir the output directory.
     * @param pCharSet the character set to use
     * @return the error or null for success
     */
    ArduinoException writeSketch(final File pOutDir,
                                 final Charset pCharSet) {
        return theSource.writeSketchToDirectory(pOutDir, pCharSet);
    }

    /**
     * Write the library output.
     * @param pOutDir the output directory.
     * @param pCharSet the character set to use
     * @return the error or null for success
     */
    ArduinoException writeLibrary(final File pOutDir,
                                  final Charset pCharSet) {
        return theSource.writeLibraryToDirectory(pOutDir, pCharSet);
    }

    /**
     * Set error.
     * @param pError the error
     */
    void setError(final ArduinoException pError) {
        theError = pError;
        theErrorLabel.setText("Error: " + theError.getMessage());
        theDetail.setText(ArduinoPanelMeta.cleanseLabelText(theError.getDetail()));
        theErrorPanel.setVisible(true);
    }

    /**
     * Clear the error.
     */
    private void clearError() {
        theError = null;
        theErrorPanel.setVisible(false);
    }

    /**
     * Handler for Window Close event.
     */
    private class WindowClose
            extends WindowAdapter {
        @Override
        public void windowClosing(final WindowEvent evt) {
            /* Dispose of the frame */
            theFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            theFrame.dispose();
        }
    }

    /**
     * Create and show the GUI.
     */
    private static void createAndShowGUI() {
        /* Protect against exceptions */
        try {
            /* Create the panel */
            new ArduinoPanelMain();

            /* Catch exceptions */
        } catch (ArduinoException e) {
            LOGGER.fatal("Failed to initialise", e);
        }
    }

    /**
     * Main function.
     * @param args the arguments
     */
    public static void main(final String[] args) {
        /* Build the GUI */
        SwingUtilities.invokeLater(ArduinoPanelMain::createAndShowGUI);
    }
}