/* Copywrite 2012-2017 Will Winder This file is part of Universal Gcode Sender (UGS). UGS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. UGS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with UGS. If not, see <http://www.gnu.org/licenses/>. */ package com.willwinder.universalgcodesender; import com.willwinder.universalgcodesender.i18n.Localization; import com.willwinder.universalgcodesender.listeners.ControllerListener; import com.willwinder.universalgcodesender.listeners.ControllerStatus; import com.willwinder.universalgcodesender.listeners.UGSEventListener; import com.willwinder.universalgcodesender.model.BackendAPI; import com.willwinder.universalgcodesender.model.GUIBackend; import com.willwinder.universalgcodesender.model.Position; import com.willwinder.universalgcodesender.model.UGSEvent; import com.willwinder.universalgcodesender.pendantui.PendantUI; import com.willwinder.universalgcodesender.services.JogService; import com.willwinder.universalgcodesender.types.GcodeCommand; import com.willwinder.universalgcodesender.uielements.UGSSettingsDialog; import com.willwinder.universalgcodesender.uielements.panels.ConnectionSettingsPanel; import com.willwinder.universalgcodesender.uielements.panels.ControllerProcessorSettingsPanel; import com.willwinder.universalgcodesender.uielements.GrblFirmwareSettingsDialog; import com.willwinder.universalgcodesender.uielements.macros.MacroPanel; import com.willwinder.universalgcodesender.uielements.panels.ActionPanel; import com.willwinder.universalgcodesender.uielements.panels.CommandPanel; import com.willwinder.universalgcodesender.uielements.panels.ConnectionPanelGroup; import com.willwinder.universalgcodesender.utils.FirmwareUtils; import com.willwinder.universalgcodesender.utils.GUIHelpers; import com.willwinder.universalgcodesender.utils.SettingsFactory; import com.willwinder.universalgcodesender.utils.Version; import org.apache.commons.lang3.SystemUtils; import javax.swing.*; import javax.swing.text.DefaultEditorKit; import java.awt.*; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collection; import java.util.logging.Logger; import static com.willwinder.universalgcodesender.utils.GUIHelpers.displayErrorDialog; import com.willwinder.universalgcodesender.visualizer.VisualizerPanel; import java.io.File; import java.util.logging.Level; /** * * @author wwinder */ public class ExperimentalWindow extends JFrame implements ControllerListener, UGSEventListener { private static final Logger logger = Logger.getLogger(ExperimentalWindow.class.getName()); final private static String VERSION = Version.getVersion() + " / " + Version.getTimestamp(); private PendantUI pendantUI; private final BackendAPI backend; private JogService jogService; /** Creates new form ExperimentalWindow */ public ExperimentalWindow() { this.backend = new GUIBackend(); try { backend.applySettings(SettingsFactory.loadSettings()); boolean fullyLocalized = Localization.initialize(backend.getSettings().getLanguage()); if (!fullyLocalized) { GUIHelpers.displayErrorDialog(Localization.getString("incomplete.localization")); } } catch (Exception e) { throw new RuntimeException(e); } if (backend.getSettings().isShowNightlyWarning() && ExperimentalWindow.VERSION.contains("nightly")) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { String message = "This version of Universal Gcode Sender is a nightly build.\n" + "It contains all of the latest features and improvements, \n" + "but may also have bugs that still need to be fixed.\n" + "\n" + "If you encounter any problems, please report them on github."; JOptionPane.showMessageDialog(new JFrame(), message, "", JOptionPane.INFORMATION_MESSAGE); }}); } initComponents(); initProgram(); backend.addControllerListener(this); backend.addUGSEventListener(this); setSize(backend.getSettings().getMainWindowSettings().width, backend.getSettings().getMainWindowSettings().height); setLocation(backend.getSettings().getMainWindowSettings().xLocation, backend.getSettings().getMainWindowSettings().yLocation); commandPanel.loadSettings(); connectionPanel.loadSettings(); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { commandPanel.saveSettings(); connectionPanel.saveSettings(); SettingsFactory.saveSettings(backend.getSettings()); if(pendantUI!=null){ pendantUI.stop(); } } }); } /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(ExperimentalWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(ExperimentalWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(ExperimentalWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(ExperimentalWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> // Fix look and feel to use CMD+C/X/V/A instead of CTRL if (SystemUtils.IS_OS_MAC) { Collection<InputMap> ims = new ArrayList<>(); ims.add((InputMap) UIManager.get("TextField.focusInputMap")); ims.add((InputMap) UIManager.get("TextArea.focusInputMap")); ims.add((InputMap) UIManager.get("EditorPane.focusInputMap")); ims.add((InputMap) UIManager.get("FormattedTextField.focusInputMap")); ims.add((InputMap) UIManager.get("PasswordField.focusInputMap")); ims.add((InputMap) UIManager.get("TextPane.focusInputMap")); int c = KeyEvent.VK_C; int v = KeyEvent.VK_V; int x = KeyEvent.VK_X; int a = KeyEvent.VK_A; int meta = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); for (InputMap im : ims) { im.put(KeyStroke.getKeyStroke(c, meta), DefaultEditorKit.copyAction); im.put(KeyStroke.getKeyStroke(v, meta), DefaultEditorKit.pasteAction); im.put(KeyStroke.getKeyStroke(x, meta), DefaultEditorKit.cutAction); im.put(KeyStroke.getKeyStroke(a, meta), DefaultEditorKit.selectAllAction); } } /* Create the form */ final ExperimentalWindow mw = new ExperimentalWindow(); /* Apply the settings to the ExperimentalWindow bofore showing it */ mw.setSize(mw.backend.getSettings().getMainWindowSettings().width, mw.backend.getSettings().getMainWindowSettings().height); mw.setLocation(mw.backend.getSettings().getMainWindowSettings().xLocation, mw.backend.getSettings().getMainWindowSettings().yLocation); mw.addComponentListener(new ComponentListener() { @Override public void componentResized(ComponentEvent ce) { mw.backend.getSettings().getMainWindowSettings().height = ce.getComponent().getSize().height; mw.backend.getSettings().getMainWindowSettings().width = ce.getComponent().getSize().width; } @Override public void componentMoved(ComponentEvent ce) { mw.backend.getSettings().getMainWindowSettings().xLocation = ce.getComponent().getLocation().x; mw.backend.getSettings().getMainWindowSettings().yLocation = ce.getComponent().getLocation().y; } @Override public void componentShown(ComponentEvent ce) {} @Override public void componentHidden(ComponentEvent ce) {} }); /* Display the form */ java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { mw.setVisible(true); } }); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { mw.connectionPanel.saveSettings(); mw.commandPanel.saveSettings(); if(mw.pendantUI!=null){ mw.pendantUI.stop(); } } }); // Check command line for a file to open. boolean open = false; for (String arg : args) { if (open) { try { mw.backend.setGcodeFile(new File(arg)); open = false; } catch (Exception ex) { Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex); System.exit(1); } } if (arg.equals("--open") || arg.equals("-o")) { open = true; } } } /** This method is called from within the constructor to * initialize the form. */ @SuppressWarnings("unchecked") private void initComponents() { // Initialize services jogService = new JogService(backend); controlContextTabbedPane = new JTabbedPane(); actionPanel = new ActionPanel(backend); macroEditPanel = new JScrollPane(); macroPanel = new MacroPanel(backend); visualizerPanel = new VisualizerPanel(backend); connectionPanel = new ConnectionPanelGroup(backend, jogService); commandPanel = new CommandPanel(backend); mainMenuBar = new JMenuBar(); settingsMenu = new JMenu(); grblConnectionSettingsMenuItem = new javax.swing.JMenuItem(); firmwareSettingsMenu = new javax.swing.JMenu(); grblFirmwareSettingsMenuItem = new javax.swing.JMenuItem(); gcodeProcessorSettings = new javax.swing.JMenuItem(); pendantMenu = new com.willwinder.universalgcodesender.uielements.components.PendantMenu(backend); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setMinimumSize(new java.awt.Dimension(640, 520)); controlContextTabbedPane.setBorder(javax.swing.BorderFactory.createTitledBorder("")); controlContextTabbedPane.setMinimumSize(new java.awt.Dimension(395, 175)); controlContextTabbedPane.setPreferredSize(new java.awt.Dimension(2000, 283)); controlContextTabbedPane.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentShown(java.awt.event.ComponentEvent evt) { controlContextTabbedPaneComponentShown(evt); } }); controlContextTabbedPane.addTab("Machine Control", actionPanel); macroEditPanel.setViewportView(macroPanel); controlContextTabbedPane.addTab("Macros", macroEditPanel); controlContextTabbedPane.addTab("Visualizer", visualizerPanel); connectionPanel.setMinimumSize(new java.awt.Dimension(1, 1)); connectionPanel.setPreferredSize(new java.awt.Dimension(275, 130)); settingsMenu.setText("Settings"); grblConnectionSettingsMenuItem.setText("Sender Settings"); grblConnectionSettingsMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { grblConnectionSettingsMenuItemActionPerformed(evt); } }); settingsMenu.add(grblConnectionSettingsMenuItem); gcodeProcessorSettings.setText("Gcode Processor Settings"); gcodeProcessorSettings.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { gcodeProcessorSettingsActionPerformed(evt); } }); settingsMenu.add(gcodeProcessorSettings); firmwareSettingsMenu.setText("Firmware Settings"); grblFirmwareSettingsMenuItem.setText("GRBL"); grblFirmwareSettingsMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { grblFirmwareSettingsMenuItemActionPerformed(evt); } }); firmwareSettingsMenu.add(grblFirmwareSettingsMenuItem); settingsMenu.add(firmwareSettingsMenu); mainMenuBar.add(settingsMenu); pendantMenu.setText("Pendant"); mainMenuBar.add(pendantMenu); setJMenuBar(mainMenuBar); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(connectionPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(controlContextTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 764, Short.MAX_VALUE) .add(commandPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(controlContextTabbedPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 294, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(commandPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)) .add(connectionPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pack(); } // TODO: It would be nice to streamline this somehow... private void grblConnectionSettingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_grblConnectionSettingsMenuItemActionPerformed UGSSettingsDialog gcsd = new UGSSettingsDialog( Localization.getString("sender.header"), backend.getSettings(), new ConnectionSettingsPanel(backend.getSettings()), this, true); gcsd.setVisible(true); if (gcsd.saveChanges()) { try { backend.applySettings(backend.getSettings()); } catch (Exception e) { displayErrorDialog(e.getMessage()); } } }//GEN-LAST:event_grblConnectionSettingsMenuItemActionPerformed private void grblFirmwareSettingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_grblFirmwareSettingsMenuItemActionPerformed try { if (!this.backend.isConnected()) { displayErrorDialog(Localization.getString("mainWindow.error.noFirmware")); } else if (this.backend.getController() instanceof GrblController) { GrblFirmwareSettingsDialog gfsd = new GrblFirmwareSettingsDialog(this, true, this.backend); gfsd.setVisible(true); } else { displayErrorDialog(Localization.getString("mainWindow.error.notGrbl")); } } catch (Exception ex) { displayErrorDialog(ex.getMessage()); } }//GEN-LAST:event_grblFirmwareSettingsMenuItemActionPerformed private void gcodeProcessorSettingsActionPerformed(java.awt.event.ActionEvent evt) { UGSSettingsDialog gcsd = new UGSSettingsDialog( Localization.getString("settings.processors.header"), backend.getSettings(), new ControllerProcessorSettingsPanel(backend.getSettings(), FirmwareUtils.getConfigFiles()), this, true); gcsd.setVisible(true); if (gcsd.saveChanges()) { // TODO: Reprocess gcode file? /* try { backend.applySettings(settings); } catch (Exception e) { displayErrorDialog(e.getMessage()); } if (this.vw != null) { vw.setMinArcLength(backend.getSettings().getSmallArcThreshold()); vw.setArcLength(backend.getSettings().getSmallArcSegmentLength()); } */ } } private void controlContextTabbedPaneComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_controlContextTabbedPaneComponentShown // TODO add your handling code here: }//GEN-LAST:event_controlContextTabbedPaneComponentShown private void initProgram() { Localization.initialize(this.backend.getSettings().getLanguage()); try { backend.applySettings(backend.getSettings()); } catch (Exception e) { displayErrorDialog(e.getMessage()); } this.setLocalLabels(); this.setTitle(Localization.getString("title") + " (" + Localization.getString("version") + " " + VERSION + ")"); // Add keyboard listener for manual controls. } /** * Updates all text labels in the GUI with localized labels. */ private void setLocalLabels() { this.controlContextTabbedPane.setTitleAt(0, Localization.getString("mainWindow.swing.controlContextTabbedPane.machineControl")); this.controlContextTabbedPane.setTitleAt(1, Localization.getString("mainWindow.swing.controlContextTabbedPane.macros")); this.controlContextTabbedPane.setTitleAt(2, Localization.getString("mainWindow.swing.visualizeButton")); this.firmwareSettingsMenu.setText(Localization.getString("mainWindow.swing.firmwareSettingsMenu")); this.grblConnectionSettingsMenuItem.setText(Localization.getString("mainWindow.swing.grblConnectionSettingsMenuItem")); this.grblFirmwareSettingsMenuItem.setText(Localization.getString("mainWindow.swing.grblFirmwareSettingsMenuItem")); this.settingsMenu.setText(Localization.getString("mainWindow.swing.settingsMenu")); this.macroEditPanel.setToolTipText(Localization.getString("mainWindow.swing.macroInstructions")); this.pendantMenu.setText(Localization.getString("mainWindow.swing.pendant")); this.gcodeProcessorSettings.setText(Localization.getString("settings.processors.header")); } /** * SerialCommunicatorListener implementation. */ @Override public void controlStateChange(UGSEvent.ControlState state) { } @Override public void fileStreamComplete(String filename, boolean success) { final String durationLabelCopy = connectionPanel.getDuration(); if (success) { java.awt.EventQueue.invokeLater(() -> { JOptionPane.showMessageDialog(new JFrame(), Localization.getString("mainWindow.ui.jobComplete") + " " + durationLabelCopy, Localization.getString("success"), JOptionPane.INFORMATION_MESSAGE); try { Thread.sleep(1000); } catch (InterruptedException ex) {} }); } else { displayErrorDialog(Localization.getString("mainWindow.error.jobComplete")); } } @Override public void commandSkipped(GcodeCommand command) { } @Override public void commandSent(final GcodeCommand command) { } @Override public void commandComment(String comment) { } @Override public void commandComplete(final GcodeCommand command) { } @Override public void probeCoordinates(Position p) { } @Override public void messageForConsole(MessageType type, String msg) { } @Override public void statusStringListener(ControllerStatus status) { } @Override public void postProcessData(int numRows) { } @Override public void UGSEvent(UGSEvent evt) { } private com.willwinder.universalgcodesender.uielements.panels.ActionPanel actionPanel; private com.willwinder.universalgcodesender.uielements.panels.CommandPanel commandPanel; private com.willwinder.universalgcodesender.uielements.panels.ConnectionPanelGroup connectionPanel; private javax.swing.JTabbedPane controlContextTabbedPane; private javax.swing.JMenu firmwareSettingsMenu; private javax.swing.JMenuItem grblConnectionSettingsMenuItem; private javax.swing.JMenuItem grblFirmwareSettingsMenuItem; private javax.swing.JMenuItem gcodeProcessorSettings; private javax.swing.JScrollPane macroEditPanel; private com.willwinder.universalgcodesender.uielements.macros.MacroPanel macroPanel; private javax.swing.JMenuBar mainMenuBar; private com.willwinder.universalgcodesender.uielements.components.PendantMenu pendantMenu; private javax.swing.JMenu settingsMenu; private com.willwinder.universalgcodesender.visualizer.VisualizerPanel visualizerPanel; }