package bs.bs2d.gui;
import bs.bs2d.fea.FEAResults;
import bs.bs2d.gui.views.BSGUIView;
import bs.bs2d.gui.views.MeshView;
import bs.bs2d.fea.TriMesh2D;
import bs.bs2d.gui.plot.PlotPanel;
import bs.bs2d.gui.plot.Plottable;
import bs.bs2d.gui.views.GCodeView;
import bs.bs2d.gui.views.InfillAreaView;
import bs.bs2d.gui.views.ResultProcessingView;
import bs.bs2d.gui.views.LoadcaseView;
import bs.bs2d.gui.views.ResultView;
import bs.bs2d.io.Gmsh;
import bs.bs2d.io.MeshReader;
import bs.properties.BSProperties;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import org.apache.commons.io.FileUtils;
/**
*
* @author Djen
*/
public class MainGUI{
public static boolean DEBUG_LOADCASE = false;
public static boolean DEBUG_RESULTS = true;
JFrame mainFrame;
// GUI components ////////////////////
BSGUIView[] views;
JMenuBar menuBar;
JMenu[] menus;
JSplitPane contentPanel;
JLabel title;
JButton btnNext, btnPrev;
int currentView;
private BusyStateListener bsl;
public MainGUI(){
readConfig();
currentView = 0;
initMainFrame();
initViews();
initContentPanel();
mainFrame.add(getNavigationPanel(), BorderLayout.PAGE_START);
mainFrame.add(contentPanel, BorderLayout.CENTER);
initMenu();
mainFrame.setJMenuBar(menuBar);
mainFrame.setMinimumSize(new Dimension(600, 400));
}
public void show(){
changeView(0);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
private void initMainFrame() {
mainFrame = new JFrame("BoneSlicer");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setPreferredSize(new Dimension(900, 600));
mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
writeConfig();
}
});
JPanel glass = (JPanel) mainFrame.getGlassPane();
glass.setLayout(new GridBagLayout());
JLabel l = new JLabel("Busy...");
l.setOpaque(true);
l.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createBevelBorder(BevelBorder.RAISED),
BorderFactory.createEmptyBorder(30, 80, 30, 80)));
glass.add(l);
glass.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
Toolkit.getDefaultToolkit().beep();
}
});
}
private void initViews(){
views = new BSGUIView[6];
views[0] = new MeshView();
views[1] = new LoadcaseView();
views[2] = new ResultView();
views[3] = new ResultProcessingView();
views[4] = new InfillAreaView();
views[5] = new GCodeView();
// pass on busyStateListener so each view can invoke buys state
bsl = new BusyStateListener() {
@Override
public void setBusy(boolean busy) {
mainFrame.getGlassPane().setVisible(busy);
}
};
for (BSGUIView view : views) {
view.setBusyStateListener(bsl);
}
}
private void initMenu() {
menuBar = new JMenuBar();
JMenu menuFile = new JMenu("File");
JMenuItem mitOpenGeom = new JMenuItem("Open Geometry...");
mitOpenGeom.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// choose geometry file
File f = BSConstants.workFile;
JFileChooser fc = new JFileChooser(f);
fc.setFileFilter(Gmsh.getGeometryFilter());
int result = fc.showOpenDialog(null);
if(result != JFileChooser.APPROVE_OPTION)
return;
f = fc.getSelectedFile();
BSConstants.workFile = f;
// init mesh view with selected file
views[0].init(f);
changeView(0);
}
});
menuFile.add(mitOpenGeom);
JMenuItem mitOpenMesh = new JMenuItem("Open Mesh...");
mitOpenMesh.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// choose mesh file
File f = BSConstants.workFile;
JFileChooser fc = new JFileChooser(f);
fc.setFileFilter(MeshReader.getFileFilter());
int result = fc.showOpenDialog(null);
if(result != JFileChooser.APPROVE_OPTION)
return;
f = fc.getSelectedFile();
BSConstants.workFile = f;
// init mesh view with selected file
try {
TriMesh2D mesh = MeshReader.readMesh(f);
views[0].init(mesh);// give mesh to mesh view (0)
changeView(1); //mesh will be passed on to loadcase view (1)
} catch (Exception ex) {
UserMessage.showError("Error opening file!",
ex.getMessage());
}
}
});
menuFile.add(mitOpenMesh);
JMenuItem mitOpenFEA = new JMenuItem("Open FEA Results...");
mitOpenFEA.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// choose dat file
JFileChooser fc = new JFileChooser(BSConstants.workFile);
fc.setFileFilter(FEAResults.getFileFilter());
int result = fc.showOpenDialog(null);
if(result != JFileChooser.APPROVE_OPTION)
return;
final File f = fc.getSelectedFile();
BSConstants.workFile = f;
// init mesh view with selected file
try {
currentView = 2; // make sure no data gets passed on from previous view
changeView(2); //show result view (2)
bsl.setBusy(true);
new Thread(new Runnable() {
@Override
public void run() {
FEAResults results = FEAResults.getResultsFromFile(f);
views[2].init(results);// init result view (2)
bsl.setBusy(false);
}
}).start();
} catch (Exception ex) {
UserMessage.showError("Error opening file!",
ex.getMessage());
}
}
});
menuFile.add(mitOpenFEA);
menuFile.addSeparator();
JMenuItem mitExit = new JMenuItem("Exit");
mitExit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WindowEvent we;
we = new WindowEvent(mainFrame, WindowEvent.WINDOW_CLOSING);
mainFrame.dispatchEvent(we);
}
});
menuFile.add(mitExit);
JMenu menuScrnSht = new JMenu("Screenshot");
JMenuItem mitSStoCB = new JMenuItem("To Clipboard");
mitSStoCB.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
PlotPanel content = (PlotPanel)contentPanel.getTopComponent();
Plottable plot = content.getPlotObject();
Rectangle2D plotBounds = plot.getBounds();
Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, 400, 400);
AffineTransform t1 = AffineTransform.getTranslateInstance(-plotBounds.getX(), -plotBounds.getY());
double scale = Math.min(imgBounds.getWidth()/plotBounds.getWidth(), imgBounds.getHeight()/plotBounds.getHeight());
AffineTransform s = AffineTransform.getScaleInstance(scale, -scale);
AffineTransform t2 = AffineTransform.getTranslateInstance(0, plotBounds.getHeight()*scale + 1);
s.concatenate(t1);
t2.concatenate(s);
Rectangle2D tbounds = t2.createTransformedShape(plotBounds).getBounds2D();
BufferedImage img = new BufferedImage((int)tbounds.getWidth()+2, (int)tbounds.getHeight()+2, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D)img.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
plot.paint(g, t2);
TransferableImage ti = new TransferableImage(img);
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
c.setContents( ti, null );
System.out.println("An image of plot has been copied to the clipboard.");
}
});
menuScrnSht.add(mitSStoCB);
menus = new JMenu[] {menuFile, menuScrnSht};
}
private JPanel getNavigationPanel(){
JPanel p = new JPanel(new BorderLayout());
title = new JLabel("", JLabel.CENTER);
title.setFont(new Font(Font.DIALOG, Font.BOLD, 18));
p.add(title);
btnNext = new JButton("Next Step ->");
btnNext.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changeView(currentView + 1);
}
});
btnPrev = new JButton("<- Previous Step");
btnPrev.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changeView(currentView - 1);
}
});
p.add(btnPrev, BorderLayout.LINE_START);
p.add(btnNext, BorderLayout.LINE_END);
return p;
}
private void initContentPanel(){
contentPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
contentPanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
updateDivider();
}
});
}
/**
* Resets the divider to respect the preferred size of the right component.
*/
private void updateDivider(){
Dimension ps = views[currentView].getControls().getPreferredSize();
int width = contentPanel.getWidth();
int pos = width - ps.width - contentPanel.getDividerSize() - 1;
contentPanel.setDividerLocation(pos);
}
private void changeView(int view){
// update navigation bar
title.setText((view + 1) + ". " + views[view].getName());
btnPrev.setEnabled(view > 0);
btnNext.setEnabled(view < views.length - 1);
// update content
if(view > currentView) // pass on data
views[view].init(views[view - 1].getData());
contentPanel.setTopComponent(views[view].getContent());
contentPanel.setBottomComponent(views[view].getControls());
updateDivider();
// update menu
menuBar.removeAll();
for (JMenu m : menus)
menuBar.add(m);
for (JMenu m : views[view].getMenus())
menuBar.add(m);
currentView = view;
}
// main /////////////////////////////////////
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException |
IllegalAccessException | UnsupportedLookAndFeelException e) {
System.err.println("Unable to set system look and feel.");
}
readConfig();
try {
checkPropertyFiles();
} catch (IOException | URISyntaxException | RuntimeException ex) {
ex.printStackTrace();
}
MainGUI mgui = new MainGUI();
mgui.mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
writeConfig();
}
});
mgui.show();
}
private static void checkPropertyFiles() throws IOException, URISyntaxException{
File print = FileUtils.getFile(BSConstants.SETTINGS_DIR,
BSConstants.PRINT_DIR_NAME);
File printer = FileUtils.getFile(BSConstants.SETTINGS_DIR,
BSConstants.PRINTER_DIR_NAME);
File filament = FileUtils.getFile(BSConstants.SETTINGS_DIR,
BSConstants.FILAMENT_DIR_NAME);
print.mkdirs();
printer.mkdirs();
filament.mkdirs();
String defini = "default.ini";
if(print.listFiles(BSConstants.INI_EXTENSION_FILTER).length == 0){
print = FileUtils.getFile(print, defini);
String s = BSProperties.DEFAULT_PRINT_PROPERTY_FILE;
InputStream is = BSProperties.getResource(s);
FileUtils.copyInputStreamToFile(is, print);
}
if(printer.listFiles(BSConstants.INI_EXTENSION_FILTER).length == 0){
printer = FileUtils.getFile(printer, defini);
String s = BSProperties.DEFAULT_PRINTER_PROPERTY_FILE;
InputStream is = BSProperties.getResource(s);
FileUtils.copyInputStreamToFile(is, printer);
}
if(filament.listFiles(BSConstants.INI_EXTENSION_FILTER).length == 0){
filament = FileUtils.getFile(filament, defini);
String s = BSProperties.DEFAULT_FILAMENT_PROPERTY_FILE;
InputStream is = BSProperties.getResource(s);
FileUtils.copyInputStreamToFile(is, filament);
}
}
private static void writeConfig(){
System.out.println("writing config");
try{
File f = FileUtils.getFile(BSConstants.SETTINGS_DIR, BSConstants.BSCONFIG_FILE_NAME);
FileUtils.write(f, BSConstants.workFile.getPath());
} catch (IOException ex){
ex.printStackTrace();
}
}
private static void readConfig(){
try {
File f = FileUtils.getFile(BSConstants.SETTINGS_DIR, BSConstants.BSCONFIG_FILE_NAME);
List<String> lines = FileUtils.readLines(f);
BSConstants.workFile = new File(lines.get(0));
} catch (IOException | RuntimeException e) { }
}
}