ArduinoPanelSource.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.CardLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.Border;
import net.sourceforge.jarduino.ArduinoException;
import net.sourceforge.jarduino.message.ArduinoChar;
import net.sourceforge.jarduino.message.ArduinoLibrary;
import net.sourceforge.jarduino.message.ArduinoGenerator;
import net.sourceforge.jarduino.message.ArduinoMsgFilter;
import net.sourceforge.jarduino.message.ArduinoParser;
import net.sourceforge.jarduino.message.ArduinoSystem;
/**
* Panel for displaying sources.
*/
public class ArduinoPanelSource {
/**
* Filter panel name.
*/
private static final String FILTER = "Filter";
/**
* Source panel name.
*/
private static final String SOURCE = "Source";
/**
* Font.
*/
static final Font FONT = new Font("monospaced", Font.PLAIN, 12);
/**
* The Panel.
*/
private final JPanel thePanel;
/**
* The FileSetButton.
*/
private final ArduinoScrollButton<ArduinoFileSet> theFileSetButton;
/**
* The FileButton.
*/
private final ArduinoScrollButton<ArduinoFile> theFileButton;
/**
* The textArea.
*/
private final JTextArea theSourceFile;
/**
* The filter panel.
*/
private final ArduinoPanelFilter theFilterPanel;
/**
* The current system.
*/
private ArduinoSystem theSystem;
/**
* The sourceDBC.
*/
private String theDBCFile;
/**
* The error.
*/
private ArduinoException theError;
/**
* Constructor.
* @param pFrame the frame
*/
ArduinoPanelSource(final JFrame pFrame) {
/* Create the panel */
thePanel = new JPanel(new CardLayout());
/* Create the filter panel */
theFilterPanel = new ArduinoPanelFilter(this, pFrame);
/* Create the TextPane */
theSourceFile = new JTextArea();
theSourceFile.setEditable(false);
theSourceFile.setFont(FONT);
/* Create the Filter button */
final JButton myFilterButton = new JButton();
myFilterButton.setText("Sources");
myFilterButton.addActionListener(e -> showFilter());
/* Create the file button */
theFileButton = new ArduinoScrollButton<>(pFrame);
theFileButton.onSelect(this::showSourceFile);
theFileButton.setFormatter(e -> e.getFileName(theSystem));
/* Create the fileSet button */
theFileSetButton = new ArduinoScrollButton<>(pFrame);
theFileSetButton.onSelect(this::populateFileSet);
for (ArduinoFileSet myFileSet : ArduinoFileSet.values()) {
theFileSetButton.add(myFileSet);
}
/* Create the file panel */
final JPanel myFilePanel = new JPanel();
myFilePanel.setLayout(new BoxLayout(myFilePanel, BoxLayout.X_AXIS));
myFilePanel.add(Box.createHorizontalStrut(ArduinoPanelMain.STRUTSIZE));
myFilePanel.add(theFileSetButton.getComponent());
myFilePanel.add(Box.createHorizontalStrut(ArduinoPanelMain.STRUTSIZE));
myFilePanel.add(theFileButton.getComponent());
myFilePanel.add(Box.createHorizontalGlue());
Border myBorder = BorderFactory.createTitledBorder("Select File To View");
myFilePanel.setBorder(myBorder);
/* Create the filter panel */
final JPanel myFilterPanel = new JPanel();
myFilterPanel.setLayout(new BoxLayout(myFilterPanel, BoxLayout.X_AXIS));
myFilterPanel.add(Box.createHorizontalStrut(ArduinoPanelMain.STRUTSIZE));
myFilterPanel.add(myFilterButton);
myFilterPanel.add(Box.createHorizontalStrut(ArduinoPanelMain.STRUTSIZE));
myBorder = BorderFactory.createTitledBorder("View");
myFilterPanel.setBorder(myBorder);
/* Create the control panel */
final JPanel myControl = new JPanel();
myControl.setLayout(new BoxLayout(myControl, BoxLayout.X_AXIS));
myControl.add(myFilePanel);
myControl.add(myFilterPanel);
/* Create the fileView */
final JPanel myFileView = new JPanel(new BorderLayout());
myFileView.add(new JScrollPane(theSourceFile), BorderLayout.CENTER);
myBorder = BorderFactory.createTitledBorder(SOURCE);
myFileView.setBorder(myBorder);
/* Create the main Panel */
final JPanel mySource = new JPanel(new BorderLayout());
mySource.add(myControl, BorderLayout.PAGE_START);
mySource.add(myFileView, BorderLayout.CENTER);
/* Build the panel */
thePanel.add(mySource, SOURCE);
thePanel.add(theFilterPanel.getComponent(), FILTER);
/* Set Dimensions */
thePanel.setPreferredSize(new Dimension(ArduinoPanelMain.WIDTH, ArduinoPanelMain.HEIGHT));
}
/**
* Obtain the component.
* @return the component
*/
JComponent getComponent() {
return thePanel;
}
/**
* Obtain the system.
* @return the system
*/
ArduinoSystem getSystem() {
return theSystem;
}
/**
* Obtain the error.
* @return the error
*/
ArduinoException getError() {
return theError;
}
/**
* Show Filter Panel.
*/
private void showFilter() {
((CardLayout) thePanel.getLayout()).show(thePanel, FILTER);
}
/**
* Show Source Panel.
*/
void showSource() {
((CardLayout) thePanel.getLayout()).show(thePanel, SOURCE);
}
/**
* Update the filter.
*/
void updateFilter() {
showSourceFile(theFileButton.getSelectedItem());
}
/**
* Set selected.
* @param pSource the selected file
* @param pCharSet the character set to use
* @return success true/false
*/
boolean setSelected(final File pSource,
final Charset pCharSet) {
/* Protect against exceptions */
try {
/* Clear the error */
theError = null;
/* Load the file */
final ArduinoSystem mySystem = ArduinoParser.parseFile(pSource, pCharSet);
/* Load the source file */
theDBCFile = loadSource(pSource, pCharSet);
/* Record the successful system and update the filter */
theSystem = mySystem;
theFilterPanel.setSystem(mySystem);
theFileSetButton.setSelectedItem(ArduinoFileSet.SRCDBC);
return true;
/* Handle exceptions */
} catch (ArduinoException e) {
/* Record the error and return */
theError = e;
return false;
}
}
/**
* Set System.
* @param pFile the source file
*/
private void showSourceFile(final ArduinoFile pFile) {
/* Set Base Headers */
theSourceFile.setText(getSourceText(pFile));
theSourceFile.setCaretPosition(0);
}
/**
* populate FileButton for fileSet.
* @param pFileSet the fileSet
*/
private void populateFileSet(final ArduinoFileSet pFileSet) {
/* Set Base Headers */
theFileButton.removeAll();
for (ArduinoFile myFile : ArduinoFile.values()) {
if (myFile.isInFileSet(pFileSet)) {
theFileButton.add(myFile);
}
}
}
/**
* Obtain source text.
* @param pFile the source file
* @return the source text
*/
private String getSourceText(final ArduinoFile pFile) {
/* Handle initialisation case */
if (theSystem == null) {
return null;
}
/* Switch on file */
switch (pFile) {
case BASEHEADER:
return ArduinoLibrary.loadLibraryHeader();
case BASEBODY:
return ArduinoLibrary.loadLibraryCode();
case SRCHEADER:
return ArduinoGenerator.formatHeader(theSystem, theFilterPanel.getFilter());
case SRCBODY:
return ArduinoGenerator.formatBody(theSystem, theFilterPanel.getFilter());
case DBCFILE:
default:
return theDBCFile;
}
}
/**
* Load Source.
* @param pSource the source.
* @param pCharSet the character set to use
* @return the source
* @throws ArduinoException on error
*/
private static String loadSource(final File pSource,
final Charset pCharSet) throws ArduinoException {
/* Protect against exceptions */
try (FileInputStream myStream = new FileInputStream(pSource);
InputStreamReader myReader = new InputStreamReader(myStream, pCharSet);
BufferedReader myInput = new BufferedReader(myReader)) {
/* Reset the builder */
final StringBuilder myBuilder = new StringBuilder();
/* Read the header entry */
for (;;) {
/* Read next line */
final String myLine = myInput.readLine();
if (myLine == null) {
break;
}
/* Add to the string buffer */
myBuilder.append(myLine);
myBuilder.append(ArduinoChar.LF);
}
/* Build the string */
return myBuilder.toString();
/* Catch exceptions */
} catch (IOException e) {
throw new ArduinoException("Failed to load File");
}
}
/**
* Write Sketch Files to directory.
* @param pDirectory the directory to write to
* @param pCharSet the character set to use
* @return the exception (or null if successful)
*/
ArduinoException writeSketchToDirectory(final File pDirectory,
final Charset pCharSet) {
/* Protect against exceptions */
try {
/* Obtain the message filter */
final ArduinoMsgFilter myFilter = theFilterPanel.getFilter();
/* Write system header */
File myFile = new File(pDirectory, ArduinoFile.SRCHEADER.getFileName(theSystem));
writeStringToFile(ArduinoGenerator.formatHeader(theSystem, myFilter), pCharSet, myFile);
/* Write system code */
myFile = new File(pDirectory, ArduinoFile.SRCBODY.getFileName(theSystem));
writeStringToFile(ArduinoGenerator.formatBody(theSystem, myFilter), pCharSet, myFile);
/* Signal OK */
return null;
/* Catch exceptions */
} catch (ArduinoException e) {
return e;
}
}
/**
* Write Files to directory.
* @param pDirectory the directory to write to
* @param pCharSet the character set to use
* @return the exception (or null if successful)
*/
ArduinoException writeLibraryToDirectory(final File pDirectory,
final Charset pCharSet) {
/* Protect against exceptions */
try {
/* Write base header */
File myFile = new File(pDirectory, ArduinoFile.BASEHEADER.getFileName(theSystem));
writeStringToFile(ArduinoLibrary.loadLibraryHeader(), pCharSet, myFile);
/* Write base code */
myFile = new File(pDirectory, ArduinoFile.BASEBODY.getFileName(theSystem));
writeStringToFile(ArduinoLibrary.loadLibraryCode(), pCharSet, myFile);
/* Signal OK */
return null;
/* Catch exceptions */
} catch (ArduinoException e) {
return e;
}
}
/**
* Write String to file.
* @param pData the String to write
* @param pCharSet the characterSet to use
* @param pFile the file to write to
* @throws ArduinoException on error
*/
private static void writeStringToFile(final String pData,
final Charset pCharSet,
final File pFile) throws ArduinoException {
/* Protect the write */
try (PrintWriter myWriter = new PrintWriter(pFile, pCharSet.name())) {
/* Write the data to the file */
myWriter.print(pData);
} catch (IOException e) {
throw new ArduinoException("Failed to output to file", pFile.getAbsolutePath());
}
}
/**
* The source files.
*/
private enum ArduinoFile {
/**
* Source Header.
*/
SRCHEADER,
/**
* Source Body.
*/
SRCBODY,
/**
* Base Header.
*/
BASEHEADER,
/**
* Base Body.
*/
BASEBODY,
/**
* DBCFile.
*/
DBCFILE;
/**
* Obtain name.
* @param pSystem the system
* @return the name
*/
String getFileName(final ArduinoSystem pSystem) {
/* Handle initialisation */
if (pSystem == null) {
return "Unknown";
}
/* Switch on file */
switch (this) {
case SRCHEADER:
return pSystem.getCName() + ".h";
case SRCBODY:
return pSystem.getCName() + ".cpp";
case BASEHEADER:
return ArduinoLibrary.HEADER;
case BASEBODY:
return ArduinoLibrary.CODE;
case DBCFILE:
default:
return pSystem.getName() + ".dbc";
}
}
/**
* is this file in the fileSet?
* @param pFileSet the fileSet
* @return true/false
*/
boolean isInFileSet(final ArduinoFileSet pFileSet) {
/* Switch on file */
switch (this) {
case SRCBODY:
case SRCHEADER:
return ArduinoFileSet.SKETCH.equals(pFileSet);
case BASEHEADER:
case BASEBODY:
return ArduinoFileSet.LIBRARY.equals(pFileSet);
case DBCFILE:
default:
return ArduinoFileSet.SRCDBC.equals(pFileSet);
}
}
}
/**
* The fileSet files.
*/
private enum ArduinoFileSet {
/**
* Source DBC.
*/
SRCDBC,
/**
* Sketch.
*/
SKETCH,
/**
* Library.
*/
LIBRARY;
@Override
public String toString() {
switch (this) {
case SRCDBC:
return "Source DBC";
case SKETCH:
return "Sketch";
case LIBRARY:
default:
return "Library";
}
}
}
}