Package com.willwinder.universalgcodesender

Source Code of com.willwinder.universalgcodesender.MainWindow

/*
* MainWindow.java
*
* Created on Jun 26, 2012, 3:04:38 PM
*/

/*
    Copywrite 2012-2014 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.pendantui.PendantUI;
import com.willwinder.universalgcodesender.pendantui.SystemStateBean;
import com.willwinder.universalgcodesender.types.GcodeCommand;
import com.willwinder.universalgcodesender.uielements.ConnectionSettingsDialog;
import com.willwinder.universalgcodesender.uielements.GcodeFileTypeFilter;
import com.willwinder.universalgcodesender.uielements.GrblFirmwareSettingsDialog;
import com.willwinder.universalgcodesender.uielements.StepSizeSpinnerModel;
import com.willwinder.universalgcodesender.visualizer.VisualizerWindow;
import com.willwinder.universalgcodesender.Version;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.text.DefaultCaret;
import javax.vecmath.Point3d;

/**
*
* @author wwinder
*/
public class MainWindow extends javax.swing.JFrame
implements KeyListener, ControllerListener, MainWindowAPI {
    private static String VERSION = Version.getVersion() + " " + Version.getTimestamp();
    private PendantUI pendantUI;
    private Settings settings;
   
    /** Creates new form MainWindow */
    public MainWindow() {
        initComponents();
        initProgram();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        lineBreakGroup = new javax.swing.ButtonGroup();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jMenuItem1 = new javax.swing.JMenuItem();
        jMenuItem3 = new javax.swing.JMenuItem();
        jMenuItem4 = new javax.swing.JMenuItem();
        scrollWindowCheckBox = new javax.swing.JCheckBox();
        bottomTabbedPane = new javax.swing.JTabbedPane();
        jScrollPane2 = new javax.swing.JScrollPane();
        consoleTextArea = new javax.swing.JTextArea();
        jScrollPane1 = new javax.swing.JScrollPane();
        commandTable = new com.willwinder.universalgcodesender.uielements.GcodeTable();
        controlContextTabbedPane = new javax.swing.JTabbedPane();
        commandsPanel = new javax.swing.JPanel();
        commandLabel = new javax.swing.JLabel();
        commandTextField = new javax.swing.JTextField();
        fileModePanel = new javax.swing.JPanel();
        sendButton = new javax.swing.JButton();
        pauseButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        visualizeButton = new javax.swing.JButton();
        browseButton = new javax.swing.JButton();
        fileTextField = new javax.swing.JTextField();
        fileLabel = new javax.swing.JLabel();
        saveButton = new javax.swing.JButton();
        fileRunPanel = new javax.swing.JPanel();
        remainingTimeValueLabel = new javax.swing.JLabel();
        sentRowsValueLabel = new javax.swing.JLabel();
        remainingRowsLabel = new javax.swing.JLabel();
        rowsValueLabel = new javax.swing.JLabel();
        remainingTimeLabel = new javax.swing.JLabel();
        durationValueLabel = new javax.swing.JLabel();
        durationLabel = new javax.swing.JLabel();
        remainingRowsValueLabel = new javax.swing.JLabel();
        sentRowsLabel = new javax.swing.JLabel();
        rowsLabel = new javax.swing.JLabel();
        machineControlPanel = new javax.swing.JPanel();
        resetCoordinatesButton = new javax.swing.JButton();
        returnToZeroButton = new javax.swing.JButton();
        keyboardMovementPanel = new javax.swing.JPanel();
        stepSizeSpinner = new javax.swing.JSpinner();
        arrowMovementEnabled = new javax.swing.JCheckBox();
        movementButtonPanel = new javax.swing.JPanel();
        zMinusButton = new javax.swing.JButton();
        yMinusButton = new javax.swing.JButton();
        xPlusButton = new javax.swing.JButton();
        xMinusButton = new javax.swing.JButton();
        zPlusButton = new javax.swing.JButton();
        yPlusButton = new javax.swing.JButton();
        stepSizeLabel = new javax.swing.JLabel();
        performHomingCycleButton = new javax.swing.JButton();
        killAlarmLock = new javax.swing.JButton();
        toggleCheckMode = new javax.swing.JButton();
        helpButtonMachineControl = new javax.swing.JButton();
        softResetMachineControl = new javax.swing.JButton();
        requestStateInformation = new javax.swing.JButton();
        resetXButton = new javax.swing.JButton();
        resetYButton = new javax.swing.JButton();
        resetZButton = new javax.swing.JButton();
        macroPanel = new javax.swing.JPanel();
        customGcodeButton4 = new javax.swing.JButton();
        customGcodeButton3 = new javax.swing.JButton();
        customGcodeButton2 = new javax.swing.JButton();
        customGcodeButton1 = new javax.swing.JButton();
        customGcodeButton5 = new javax.swing.JButton();
        customGcodeText1 = new javax.swing.JTextField();
        customGcodeText2 = new javax.swing.JTextField();
        customGcodeText3 = new javax.swing.JTextField();
        customGcodeText4 = new javax.swing.JTextField();
        customGcodeText5 = new javax.swing.JTextField();
        macroInstructions = new javax.swing.JLabel();
        connectionPanel = new javax.swing.JPanel();
        commPortComboBox = new javax.swing.JComboBox();
        baudrateSelectionComboBox = new javax.swing.JComboBox();
        opencloseButton = new javax.swing.JButton();
        refreshButton = new javax.swing.JButton();
        baudLabel = new javax.swing.JLabel();
        portLabel = new javax.swing.JLabel();
        firmwareLabel = new javax.swing.JLabel();
        firmwareComboBox = new javax.swing.JComboBox();
        showVerboseOutputCheckBox = new javax.swing.JCheckBox();
        statusPanel = new javax.swing.JPanel();
        activeStateLabel = new javax.swing.JLabel();
        activeStateValueLabel = new javax.swing.JLabel();
        machinePosition = new javax.swing.JLabel();
        machinePositionXLabel = new javax.swing.JLabel();
        machinePositionYLabel = new javax.swing.JLabel();
        machinePositionZLabel = new javax.swing.JLabel();
        workPositionLabel = new javax.swing.JLabel();
        workPositionXLabel = new javax.swing.JLabel();
        workPositionYLabel = new javax.swing.JLabel();
        workPositionZLabel = new javax.swing.JLabel();
        machinePositionXValueLabel = new javax.swing.JLabel();
        machinePositionYValueLabel = new javax.swing.JLabel();
        machinePositionZValueLabel = new javax.swing.JLabel();
        workPositionXValueLabel = new javax.swing.JLabel();
        workPositionYValueLabel = new javax.swing.JLabel();
        workPositionZValueLabel = new javax.swing.JLabel();
        latestCommentValueLabel = new javax.swing.JLabel();
        latestCommentLabel = new javax.swing.JLabel();
        mainMenuBar = new javax.swing.JMenuBar();
        settingsMenu = new javax.swing.JMenu();
        grblConnectionSettingsMenuItem = new javax.swing.JMenuItem();
        firmwareSettingsMenu = new javax.swing.JMenu();
        grblFirmwareSettingsMenuItem = new javax.swing.JMenuItem();
        PendantMenu = new javax.swing.JMenu();
        startPendantServerButton = new javax.swing.JMenuItem();
        stopPendantServerButton = new javax.swing.JMenuItem();

        jMenuItem1.setText("jMenuItem1");

        jMenuItem3.setText("jMenuItem3");

        jMenuItem4.setText("jMenuItem4");

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(640, 520));

        scrollWindowCheckBox.setSelected(true);
        scrollWindowCheckBox.setText("Scroll output window");
        scrollWindowCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                scrollWindowCheckBoxActionPerformed(evt);
            }
        });

        bottomTabbedPane.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
        bottomTabbedPane.setMinimumSize(new java.awt.Dimension(0, 0));
        bottomTabbedPane.setPreferredSize(new java.awt.Dimension(468, 100));

        consoleTextArea.setColumns(20);
        consoleTextArea.setRows(5);
        consoleTextArea.setMaximumSize(new java.awt.Dimension(32767, 32767));
        consoleTextArea.setMinimumSize(new java.awt.Dimension(0, 0));
        jScrollPane2.setViewportView(consoleTextArea);

        bottomTabbedPane.addTab("Console", jScrollPane2);

        commandTable.setModel(new com.willwinder.universalgcodesender.uielements.GcodeTableModel());
        commandTable.setMaximumSize(new java.awt.Dimension(32767, 32767));
        commandTable.getTableHeader().setReorderingAllowed(false);
        jScrollPane1.setViewportView(commandTable);

        bottomTabbedPane.addTab("Command Table", jScrollPane1);

        controlContextTabbedPane.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
        controlContextTabbedPane.setMinimumSize(new java.awt.Dimension(395, 175));

        commandLabel.setText("Command");

        commandTextField.setEnabled(false);
        commandTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                commandTextFieldActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout commandsPanelLayout = new org.jdesktop.layout.GroupLayout(commandsPanel);
        commandsPanel.setLayout(commandsPanelLayout);
        commandsPanelLayout.setHorizontalGroup(
            commandsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(commandsPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(commandsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(commandTextField)
                    .add(commandsPanelLayout.createSequentialGroup()
                        .add(commandLabel)
                        .add(0, 595, Short.MAX_VALUE)))
                .addContainerGap())
        );
        commandsPanelLayout.setVerticalGroup(
            commandsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(commandsPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(commandLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(commandTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(143, Short.MAX_VALUE))
        );

        controlContextTabbedPane.addTab("Commands", commandsPanel);

        fileModePanel.setMinimumSize(new java.awt.Dimension(389, 150));

        sendButton.setText("Send");
        sendButton.setEnabled(false);
        sendButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButtonActionPerformed(evt);
            }
        });

        pauseButton.setText("Pause");
        pauseButton.setEnabled(false);
        pauseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pauseButtonActionPerformed(evt);
            }
        });

        cancelButton.setText("Cancel");
        cancelButton.setEnabled(false);
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });

        visualizeButton.setText("Visualize");
        visualizeButton.setEnabled(false);
        visualizeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                visualizeButtonActionPerformed(evt);
            }
        });

        browseButton.setText("Browse");
        browseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                browseButtonActionPerformed(evt);
            }
        });

        fileTextField.setEnabled(false);

        fileLabel.setText("File");

        saveButton.setText("Save");
        saveButton.setEnabled(false);
        saveButton.setMaximumSize(new java.awt.Dimension(88, 29));
        saveButton.setMinimumSize(new java.awt.Dimension(88, 29));
        saveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });

        remainingTimeValueLabel.setText("--:--:--");

        sentRowsValueLabel.setText("0");

        remainingRowsLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        remainingRowsLabel.setText("Remaining Rows:");
        remainingRowsLabel.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        remainingRowsLabel.setMaximumSize(null);
        remainingRowsLabel.setMinimumSize(new java.awt.Dimension(106, 14));
        remainingRowsLabel.setPreferredSize(new java.awt.Dimension(106, 14));

        rowsValueLabel.setText("0");

        remainingTimeLabel.setText("Estimated Time Remaining:");

        durationValueLabel.setText("00:00:00");

        durationLabel.setText("Duration:");

        remainingRowsValueLabel.setText("0");

        sentRowsLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        sentRowsLabel.setText("Sent Rows:");
        sentRowsLabel.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        sentRowsLabel.setMaximumSize(null);
        sentRowsLabel.setMinimumSize(new java.awt.Dimension(106, 14));
        sentRowsLabel.setPreferredSize(new java.awt.Dimension(106, 14));

        rowsLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        rowsLabel.setText("Rows In File:");
        rowsLabel.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        rowsLabel.setMinimumSize(new java.awt.Dimension(106, 14));
        rowsLabel.setPreferredSize(new java.awt.Dimension(106, 14));

        org.jdesktop.layout.GroupLayout fileRunPanelLayout = new org.jdesktop.layout.GroupLayout(fileRunPanel);
        fileRunPanel.setLayout(fileRunPanelLayout);
        fileRunPanelLayout.setHorizontalGroup(
            fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(fileRunPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, remainingRowsLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, remainingTimeLabel)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, sentRowsLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, rowsLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, durationLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(durationValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(remainingRowsValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(sentRowsValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(remainingTimeValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(rowsValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 56, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        fileRunPanelLayout.setVerticalGroup(
            fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(fileRunPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(fileRunPanelLayout.createSequentialGroup()
                        .add(rowsValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 14, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(sentRowsValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 14, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(remainingRowsValueLabel))
                    .add(fileRunPanelLayout.createSequentialGroup()
                        .add(rowsLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 14, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(sentRowsLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 14, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(remainingRowsLabel, 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(fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(remainingTimeLabel)
                    .add(remainingTimeValueLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileRunPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(durationValueLabel)
                    .add(durationLabel))
                .addContainerGap())
        );

        org.jdesktop.layout.GroupLayout fileModePanelLayout = new org.jdesktop.layout.GroupLayout(fileModePanel);
        fileModePanel.setLayout(fileModePanelLayout);
        fileModePanelLayout.setHorizontalGroup(
            fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(fileModePanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(fileTextField)
                .addContainerGap())
            .add(org.jdesktop.layout.GroupLayout.TRAILING, fileModePanelLayout.createSequentialGroup()
                .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(fileModePanelLayout.createSequentialGroup()
                        .add(2, 2, 2)
                        .add(sendButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 68, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(pauseButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 95, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(cancelButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .add(visualizeButton))
                    .add(fileModePanelLayout.createSequentialGroup()
                        .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(fileModePanelLayout.createSequentialGroup()
                                .add(8, 8, 8)
                                .add(fileLabel))
                            .add(fileModePanelLayout.createSequentialGroup()
                                .addContainerGap()
                                .add(fileRunPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                        .add(0, 0, Short.MAX_VALUE)))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(fileModePanelLayout.createSequentialGroup()
                        .add(6, 6, 6)
                        .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(browseButton))
                .add(8, 8, 8))
        );
        fileModePanelLayout.setVerticalGroup(
            fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(fileModePanelLayout.createSequentialGroup()
                .add(fileLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileTextField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, browseButton)
                    .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(sendButton)
                        .add(pauseButton)
                        .add(cancelButton)
                        .add(visualizeButton)))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(fileModePanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(fileModePanelLayout.createSequentialGroup()
                        .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(0, 99, Short.MAX_VALUE))
                    .add(fileRunPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );

        controlContextTabbedPane.addTab("File Mode", fileModePanel);

        resetCoordinatesButton.setText("Reset Zero");
        resetCoordinatesButton.setEnabled(false);
        resetCoordinatesButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetCoordinatesButtonActionPerformed(evt);
            }
        });

        returnToZeroButton.setText("Return to Zero");
        returnToZeroButton.setEnabled(false);
        returnToZeroButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                returnToZeroButtonActionPerformed(evt);
            }
        });

        stepSizeSpinner.setModel(new StepSizeSpinnerModel(1.0, 0.0, null, 1.0));
        stepSizeSpinner.setEnabled(false);
        stepSizeSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                stepSizeSpinnerStateChanged(evt);
            }
        });

        arrowMovementEnabled.setText("Enable Keyboard Movement");
        arrowMovementEnabled.setEnabled(false);

        zMinusButton.setText("Z-");
        zMinusButton.setEnabled(false);
        zMinusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                zMinusButtonActionPerformed(evt);
            }
        });

        yMinusButton.setText("Y-");
        yMinusButton.setEnabled(false);
        yMinusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                yMinusButtonActionPerformed(evt);
            }
        });

        xPlusButton.setText("X+");
        xPlusButton.setEnabled(false);
        xPlusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                xPlusButtonActionPerformed(evt);
            }
        });

        xMinusButton.setText("X-");
        xMinusButton.setEnabled(false);
        xMinusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                xMinusButtonActionPerformed(evt);
            }
        });

        zPlusButton.setText("Z+");
        zPlusButton.setEnabled(false);
        zPlusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                zPlusButtonActionPerformed(evt);
            }
        });

        yPlusButton.setText("Y+");
        yPlusButton.setEnabled(false);
        yPlusButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                yPlusButtonActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout movementButtonPanelLayout = new org.jdesktop.layout.GroupLayout(movementButtonPanel);
        movementButtonPanel.setLayout(movementButtonPanelLayout);
        movementButtonPanelLayout.setHorizontalGroup(
            movementButtonPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(movementButtonPanelLayout.createSequentialGroup()
                .add(xMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(movementButtonPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(yPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(yMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(xPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(movementButtonPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, zMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, zPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 50, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
        );
        movementButtonPanelLayout.setVerticalGroup(
            movementButtonPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(movementButtonPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
                .add(xMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 45, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(xPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 45, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(movementButtonPanelLayout.createSequentialGroup()
                    .add(yPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 45, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(yMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 45, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .add(movementButtonPanelLayout.createSequentialGroup()
                    .add(zPlusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 46, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(zMinusButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 45, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
        );

        stepSizeLabel.setText("Step size:");
        stepSizeLabel.setEnabled(false);

        org.jdesktop.layout.GroupLayout keyboardMovementPanelLayout = new org.jdesktop.layout.GroupLayout(keyboardMovementPanel);
        keyboardMovementPanel.setLayout(keyboardMovementPanelLayout);
        keyboardMovementPanelLayout.setHorizontalGroup(
            keyboardMovementPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(arrowMovementEnabled)
            .add(keyboardMovementPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(stepSizeLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(stepSizeSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 70, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
            .add(movementButtonPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
        );
        keyboardMovementPanelLayout.setVerticalGroup(
            keyboardMovementPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(keyboardMovementPanelLayout.createSequentialGroup()
                .add(arrowMovementEnabled)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(keyboardMovementPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(stepSizeLabel)
                    .add(stepSizeSpinner, 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(movementButtonPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        keyboardMovementPanelLayout.linkSize(new java.awt.Component[] {stepSizeLabel, stepSizeSpinner}, org.jdesktop.layout.GroupLayout.VERTICAL);

        performHomingCycleButton.setText("$H");
        performHomingCycleButton.setEnabled(false);
        performHomingCycleButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                performHomingCycleButtonActionPerformed(evt);
            }
        });

        killAlarmLock.setText("$X");
        killAlarmLock.setEnabled(false);
        killAlarmLock.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                killAlarmLockActionPerformed(evt);
            }
        });

        toggleCheckMode.setText("$C");
        toggleCheckMode.setEnabled(false);
        toggleCheckMode.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toggleCheckModeActionPerformed(evt);
            }
        });

        helpButtonMachineControl.setText("Help");
        helpButtonMachineControl.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                helpButtonMachineControlActionPerformed(evt);
            }
        });

        softResetMachineControl.setText("Soft Reset");
        softResetMachineControl.setEnabled(false);
        softResetMachineControl.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                softResetMachineControlActionPerformed(evt);
            }
        });

        requestStateInformation.setText("$G");
        requestStateInformation.setEnabled(false);
        requestStateInformation.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                requestStateInformationActionPerformed(evt);
            }
        });

        resetXButton.setText("Reset X Axis");
        resetXButton.setEnabled(false);
        resetXButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetXCoordinateButtonActionPerformed(evt);
            }
        });

        resetYButton.setText("Reset Y Axis");
        resetYButton.setEnabled(false);
        resetYButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetYCoordinateButtonActionPerformed(evt);
            }
        });

        resetZButton.setText("Reset Z Axis");
        resetZButton.setEnabled(false);
        resetZButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetZCoordinateButtonActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout machineControlPanelLayout = new org.jdesktop.layout.GroupLayout(machineControlPanel);
        machineControlPanel.setLayout(machineControlPanelLayout);
        machineControlPanelLayout.setHorizontalGroup(
            machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, machineControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(machineControlPanelLayout.createSequentialGroup()
                        .add(softResetMachineControl, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 159, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(resetZButton))
                    .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
                        .add(org.jdesktop.layout.GroupLayout.LEADING, machineControlPanelLayout.createSequentialGroup()
                            .add(requestStateInformation, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .add(helpButtonMachineControl))
                        .add(org.jdesktop.layout.GroupLayout.LEADING, machineControlPanelLayout.createSequentialGroup()
                            .add(performHomingCycleButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(killAlarmLock, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(toggleCheckMode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                    .add(machineControlPanelLayout.createSequentialGroup()
                        .add(resetCoordinatesButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 159, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(resetXButton))
                    .add(machineControlPanelLayout.createSequentialGroup()
                        .add(returnToZeroButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 159, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(resetYButton)))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED, 162, Short.MAX_VALUE)
                .add(keyboardMovementPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        machineControlPanelLayout.setVerticalGroup(
            machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(machineControlPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(keyboardMovementPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(0, 80, Short.MAX_VALUE))
            .add(machineControlPanelLayout.createSequentialGroup()
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(resetCoordinatesButton)
                    .add(resetXButton))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(returnToZeroButton)
                    .add(resetYButton))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(softResetMachineControl)
                    .add(resetZButton))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(performHomingCycleButton)
                    .add(killAlarmLock)
                    .add(toggleCheckMode))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(machineControlPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(requestStateInformation)
                    .add(helpButtonMachineControl))
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        controlContextTabbedPane.addTab("Machine Control", machineControlPanel);

        customGcodeButton4.setText("C4");
        customGcodeButton4.setEnabled(false);
        customGcodeButton4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeButton4ActionPerformed(evt);
            }
        });

        customGcodeButton3.setText("C3");
        customGcodeButton3.setEnabled(false);
        customGcodeButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeButton3ActionPerformed(evt);
            }
        });

        customGcodeButton2.setText("C2");
        customGcodeButton2.setEnabled(false);
        customGcodeButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeButton2ActionPerformed(evt);
            }
        });

        customGcodeButton1.setText("C1");
        customGcodeButton1.setEnabled(false);
        customGcodeButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeButton1ActionPerformed(evt);
            }
        });

        customGcodeButton5.setText("C5");
        customGcodeButton5.setEnabled(false);
        customGcodeButton5.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeButton5ActionPerformed(evt);
            }
        });

        customGcodeText1.setText("G91 X0 Y0");
        customGcodeText1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeText1ActionPerformed(evt);
            }
        });

        customGcodeText2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeText2ActionPerformed(evt);
            }
        });

        customGcodeText3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeText3ActionPerformed(evt);
            }
        });

        customGcodeText4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeText4ActionPerformed(evt);
            }
        });

        customGcodeText5.setToolTipText("");
        customGcodeText5.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customGcodeText5ActionPerformed(evt);
            }
        });

        macroInstructions.setText("asgasg");

        org.jdesktop.layout.GroupLayout macroPanelLayout = new org.jdesktop.layout.GroupLayout(macroPanel);
        macroPanel.setLayout(macroPanelLayout);
        macroPanelLayout.setHorizontalGroup(
            macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(macroPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(customGcodeButton1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(customGcodeText1))
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(customGcodeButton2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(customGcodeText2))
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(customGcodeButton4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(customGcodeText4))
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(customGcodeButton3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(customGcodeText3))
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(customGcodeButton5, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 49, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(customGcodeText5))
                    .add(macroPanelLayout.createSequentialGroup()
                        .add(macroInstructions)
                        .add(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        macroPanelLayout.setVerticalGroup(
            macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(macroPanelLayout.createSequentialGroup()
                .add(8, 8, 8)
                .add(macroInstructions)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(customGcodeButton1)
                    .add(customGcodeText1, 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(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(customGcodeButton2)
                    .add(customGcodeText2, 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(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(customGcodeButton3)
                    .add(customGcodeText3, 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(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(customGcodeButton4)
                    .add(customGcodeText4, 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(macroPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(customGcodeButton5)
                    .add(customGcodeText5, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(76, Short.MAX_VALUE))
        );

        controlContextTabbedPane.addTab("Macros", macroPanel);

        connectionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Connection"));
        connectionPanel.setMaximumSize(new java.awt.Dimension(247, 100));
        connectionPanel.setMinimumSize(new java.awt.Dimension(247, 100));
        connectionPanel.setName("Connection"); // NOI18N
        connectionPanel.setPreferredSize(new java.awt.Dimension(247, 100));

        commPortComboBox.setEditable(true);

        baudrateSelectionComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "2400", "4800", "9600", "19200", "38400", "57600", "115200" }));
        baudrateSelectionComboBox.setSelectedIndex(2);
        baudrateSelectionComboBox.setToolTipText("Select baudrate to use for the serial port.");
        baudrateSelectionComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                baudrateSelectionComboBoxActionPerformed(evt);
            }
        });

        opencloseButton.setText("Open");
        opencloseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                opencloseButtonActionPerformed(evt);
            }
        });

        refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/refresh.gif"))); // NOI18N
        refreshButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshButtonActionPerformed(evt);
            }
        });

        baudLabel.setText("Baud:");

        portLabel.setText("Port:");

        firmwareLabel.setText("Firmware:");

        firmwareComboBox.setEditable(true);

        org.jdesktop.layout.GroupLayout connectionPanelLayout = new org.jdesktop.layout.GroupLayout(connectionPanel);
        connectionPanel.setLayout(connectionPanelLayout);
        connectionPanelLayout.setHorizontalGroup(
            connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(connectionPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(connectionPanelLayout.createSequentialGroup()
                            .add(portLabel)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(commPortComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 183, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                        .add(connectionPanelLayout.createSequentialGroup()
                            .add(baudLabel)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(baudrateSelectionComboBox, 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(refreshButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 25, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(opencloseButton)))
                    .add(connectionPanelLayout.createSequentialGroup()
                        .add(firmwareLabel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(firmwareComboBox, 0, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addContainerGap())
        );
        connectionPanelLayout.setVerticalGroup(
            connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(connectionPanelLayout.createSequentialGroup()
                .add(connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(commPortComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(portLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(baudLabel)
                        .add(baudrateSelectionComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(refreshButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 24, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(opencloseButton))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(connectionPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(firmwareLabel)
                    .add(firmwareComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(38, Short.MAX_VALUE))
        );

        showVerboseOutputCheckBox.setText("Show verbose output");

        statusPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Machine status"));
        statusPanel.setMinimumSize(new java.awt.Dimension(247, 160));
        statusPanel.setPreferredSize(new java.awt.Dimension(247, 160));

        activeStateLabel.setText("Active State:");
        activeStateLabel.setOpaque(true);

        activeStateValueLabel.setText(" ");
        activeStateValueLabel.setOpaque(true);

        machinePosition.setText("Machine Position:");

        machinePositionXLabel.setText("X:");

        machinePositionYLabel.setText("Y:");

        machinePositionZLabel.setText("Z:");

        workPositionLabel.setText("Work Position:");

        workPositionXLabel.setText("X:");

        workPositionYLabel.setText("Y:");

        workPositionZLabel.setText("Z:");

        machinePositionXValueLabel.setText("0");

        machinePositionYValueLabel.setText("0");

        machinePositionZValueLabel.setText("0");

        workPositionXValueLabel.setText("0");

        workPositionYValueLabel.setText("0");

        workPositionZValueLabel.setText("0");

        latestCommentValueLabel.setText(" ");

        latestCommentLabel.setText("Latest Comment:");

        org.jdesktop.layout.GroupLayout statusPanelLayout = new org.jdesktop.layout.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(statusPanelLayout.createSequentialGroup()
                        .add(latestCommentLabel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(latestCommentValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .add(statusPanelLayout.createSequentialGroup()
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(statusPanelLayout.createSequentialGroup()
                                .add(activeStateLabel)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(activeStateValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 120, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                            .add(statusPanelLayout.createSequentialGroup()
                                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                    .add(workPositionLabel)
                                    .add(statusPanelLayout.createSequentialGroup()
                                        .add(17, 17, 17)
                                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(workPositionZLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(workPositionZValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(workPositionYLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(workPositionYValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(workPositionXLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(workPositionXValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 65, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))))
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                    .add(machinePosition)
                                    .add(statusPanelLayout.createSequentialGroup()
                                        .add(17, 17, 17)
                                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(machinePositionZLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(machinePositionZValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(machinePositionYLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(machinePositionYValueLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                            .add(statusPanelLayout.createSequentialGroup()
                                                .add(machinePositionXLabel)
                                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                                .add(machinePositionXValueLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 65, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))))))
                        .add(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(statusPanelLayout.createSequentialGroup()
                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(activeStateLabel)
                    .add(activeStateValueLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(latestCommentLabel)
                    .add(latestCommentValueLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(statusPanelLayout.createSequentialGroup()
                        .add(workPositionLabel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(workPositionXLabel)
                            .add(workPositionXValueLabel))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(workPositionYLabel)
                            .add(workPositionYValueLabel))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(workPositionZLabel)
                            .add(workPositionZValueLabel)))
                    .add(statusPanelLayout.createSequentialGroup()
                        .add(machinePosition)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(machinePositionXLabel)
                            .add(machinePositionXValueLabel))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(machinePositionYLabel)
                            .add(machinePositionYValueLabel))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(machinePositionZLabel)
                            .add(machinePositionZValueLabel))))
                .addContainerGap(19, Short.MAX_VALUE))
        );

        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);

        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");

        startPendantServerButton.setText("Start...");
        startPendantServerButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startPendantServerButtonActionPerformed(evt);
            }
        });
        PendantMenu.add(startPendantServerButton);

        stopPendantServerButton.setText("Stop...");
        stopPendantServerButton.setEnabled(false);
        stopPendantServerButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopPendantServerButtonActionPerformed(evt);
            }
        });
        PendantMenu.add(stopPendantServerButton);

        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(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(connectionPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(statusPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .add(scrollWindowCheckBox)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(showVerboseOutputCheckBox)
                        .addContainerGap())
                    .add(controlContextTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
            .add(bottomTabbedPane, 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()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .add(connectionPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 144, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(statusPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(layout.createSequentialGroup()
                        .add(controlContextTabbedPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 283, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(scrollWindowCheckBox)
                            .add(showVerboseOutputCheckBox))))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(bottomTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    /** End of generated code.
     */
   
    /** Generated callback functions, hand coded.
     */
    private void scrollWindowCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scrollWindowCheckBoxActionPerformed
        checkScrollWindow();
    }//GEN-LAST:event_scrollWindowCheckBoxActionPerformed

    private void commandTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commandTextFieldActionPerformed
        final String str = this.commandTextField.getText().replaceAll("(\\r\\n|\\n\\r|\\r|\\n)", "");
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    controller.queueStringForComm(str);
                } catch (Exception ex) {
                    displayErrorDialog(ex.getMessage());
                }
            }
        });
        this.commandTextField.setText("");
        this.manualCommandHistory.add(str);
        this.commandNum = -1;
    }//GEN-LAST:event_commandTextFieldActionPerformed
   
    @Override
  public void sendGcodeCommand(String commandText){
        this.commandTextField.setText(commandText);
        commandTextFieldActionPerformed(new ActionEvent(commandTextField, 1, "sendCommand"));
    }

    // TODO: Find out how to make these key* functions actions like the above.
    // TODO: Create custom text area that will do all this stuff without
    //       cluttering up the MainWindow class.
    @Override
    public void keyPressed(KeyEvent ke) {
        boolean pressed = false;
       
        if (ke.getKeyCode() == KeyEvent.VK_UP) {
            pressed = true;
            if (this.commandNum == 0 || this.manualCommandHistory.isEmpty()) {
                java.awt.Toolkit.getDefaultToolkit().beep();
            } else if (this.commandNum == -1) {
                this.commandNum = this.manualCommandHistory.size() -1;
            } else {
                this.commandNum--;
            }
        }
        else if (ke.getKeyCode() == KeyEvent.VK_DOWN) {
            pressed = true;
            if ((this.commandNum == -1) || this.commandNum == (this.manualCommandHistory.size() -1)) {
                java.awt.Toolkit.getDefaultToolkit().beep();
                return;
            } else {
                this.commandNum++;
            }
        }
       
        if (pressed && this.commandNum != -1) {
            String text = this.manualCommandHistory.get(this.commandNum);
            this.commandTextField.setText(text);
        }
    }
   
    @Override
    public void keyTyped(KeyEvent ke) {
        // Don't care about this one...
    }
   
    @Override
    public void keyReleased(KeyEvent ke) {
        // Or this one...
    }
   
    private void opencloseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_opencloseButtonActionPerformed
        if( this.opencloseButton.getText().equalsIgnoreCase("open") ) {
            // Hook the view up to the model
            String firmware = this.firmwareComboBox.getSelectedItem().toString();
            this.controller = FirmwareUtils.getControllerFor(firmware);

            applySettingsToController(this.controller);
           
            // Register comm listeners
            this.controller.addListener(this);
            if (vw != null) {
                this.controller.addListener(vw);
                vw.setMinArcLength(this.controller.getSmallArcThreshold());
                vw.setArcLength(this.controller.getSmallArcSegmentLength());
            }
            if (pendantUI != null) {
                this.controller.addListener(pendantUI);
            }
           
            Boolean ret = openCommConnection();

            if (ret) {
                this.updateControlsForState(ControlState.COMM_IDLE);
                if (this.gcodeFile != null) {
                    try {
                        loadFile(this.gcodeFile);
                    } catch (FileNotFoundException ex) {
                        MainWindow.displayErrorDialog(Localization.getString(
                                "mainWindow.error.openingFile") +": " + ex.getMessage());
                    } catch (IOException e) {
                        MainWindow.displayErrorDialog(Localization.getString(
                                "mainWindow.error.processingFile") +": " + e.getMessage());
                    }
                }
                // Let the command field grab focus.
                commandTextField.grabFocus();
            }
        } else {
            this.closeCommConnection();
            this.updateControlsForState(ControlState.COMM_DISCONNECTED);
        }
    }//GEN-LAST:event_opencloseButtonActionPerformed

    private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
        loadPortSelector();
    }//GEN-LAST:event_refreshButtonActionPerformed

    private void baudrateSelectionComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_baudrateSelectionComboBoxActionPerformed
    }//GEN-LAST:event_baudrateSelectionComboBoxActionPerformed


    private void increaseStepActionPerformed(java.awt.event.ActionEvent evt) {                                            
        double stepSize = this.getStepSize();
        if (stepSize >= 1) {
            stepSize++;
        } else if (stepSize >= 0.1) {
            stepSize = stepSize + 0.1;
        } else if (stepSize >= 0.01) {
            stepSize = stepSize + 0.01;
        } else {
            stepSize = 0.01;
        }
        this.setStepSize(stepSize);
    }                                           

    private void decreaseStepActionPerformed(java.awt.event.ActionEvent evt) {                                            
        double stepSize = this.getStepSize();
        if (stepSize > 1) {           
            stepSize--;
        } else if (stepSize > 0.1) {
            stepSize = stepSize - 0.1;
        } else if (stepSize > 0.01) {
            stepSize = stepSize - 0.01;
        }
        this.setStepSize(stepSize);
    }                                           
   
    private void divideStepActionPerformed(java.awt.event.ActionEvent evt) {                                            
        double stepSize = this.getStepSize();

        if (stepSize > 100) {           
            stepSize = 100;
        } else if (stepSize <= 100 && stepSize > 10) {
            stepSize = 10;
        } else if (stepSize <= 10 && stepSize > 1) {
            stepSize = 1;
        } else if (stepSize <= 1 && stepSize > 0.1) {
            stepSize = 0.1;
        } else if (stepSize <= 0.1 ) {
            stepSize = 0.01;
        }
       
        this.setStepSize(stepSize);
    }                                           

    private void multiplyStepActionPerformed(java.awt.event.ActionEvent evt) {                                            
        double stepSize = this.getStepSize();

        if (stepSize < 0.01) {           
            stepSize = 0.01;
        } else if (stepSize >= 0.01 && stepSize < 0.1) {           
            stepSize = 0.1;
        else if (stepSize >= 0.1 && stepSize < 1) {           
            stepSize = 1;
        else if (stepSize >= 1 && stepSize < 10) {           
            stepSize = 10;
        else if (stepSize >= 10) {           
            stepSize = 100;
        }

        this.setStepSize(stepSize);
    }                                           
   
    @Override
    public  void resetCoordinatesButtonActionPerformed(){
        try {
            this.controller.resetCoordinatesToZero();
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }

    @Override
    public  void resetXCoordinateButtonActionPerformed(){
        try {
            this.controller.resetCoordinateToZero('X');
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }

    @Override
    public  void resetYCoordinateButtonActionPerformed(){
        try {
            this.controller.resetCoordinateToZero('Y');
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }

    @Override
    public  void resetZCoordinateButtonActionPerformed(){
        try {
            this.controller.resetCoordinateToZero('Z');
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }

                                               

    @Override
    public void returnToZeroButtonActionPerformed(){
        try {
            this.controller.returnToHome();
            // The return to home command uses G91 to lift the tool.
            this.G91Mode = true;
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }
    // TODO: It would be nice to streamline this somehow...
    private void grblConnectionSettingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_grblConnectionSettingsMenuItemActionPerformed
        ConnectionSettingsDialog gcsd = new ConnectionSettingsDialog(this, true);
       
        // Set initial values.
        gcsd.setSpeedOverrideEnabled(settings.isOverrideSpeedSelected());
        gcsd.setSpeedOverridePercent((int) settings.getOverrideSpeedValue());
        gcsd.setMaxCommandLength(settings.getMaxCommandLength());
        gcsd.setTruncateDecimalLength(settings.getTruncateDecimalLength());
        gcsd.setSingleStepModeEnabled(settings.isSingleStepMode());
        gcsd.setRemoveAllWhitespace(settings.isRemoveAllWhitespace());
        gcsd.setStatusUpdatesEnabled(settings.isStatusUpdatesEnabled());
        gcsd.setStatusUpdatesRate(settings.getStatusUpdateRate());
        gcsd.setStateColorDisplayEnabled(settings.isDisplayStateColor());
        gcsd.setConvertArcsToLines(settings.isConvertArcsToLines());
        gcsd.setSmallArcThreshold(settings.getSmallArcThreshold());
        gcsd.setSmallArcSegmentLengthSpinner(settings.getSmallArcSegmentLength());
        gcsd.setVisible(true);
       
        if (gcsd.saveChanges()) {
            settings.setOverrideSpeedSelected(gcsd.getSpeedOverrideEnabled());
            settings.setOverrideSpeedValue(gcsd.getSpeedOverridePercent());
            settings.setMaxCommandLength(gcsd.getMaxCommandLength());
            settings.setTruncateDecimalLength(gcsd.getTruncateDecimalLength());
            settings.setSingleStepMode(gcsd.getSingleStepModeEnabled());
            settings.setRemoveAllWhitespace(gcsd.getRemoveAllWhitespace());
            settings.setStatusUpdatesEnabled(gcsd.getStatusUpdatesEnabled());
            settings.setStatusUpdateRate(gcsd.getStatusUpdatesRate());
            settings.setDisplayStateColor(gcsd.getDisplayStateColor());
            settings.setConvertArcsToLines(gcsd.getConvertArcsToLines());
            settings.setSmallArcThreshold(gcsd.getSmallArcThreshold());
            settings.setSmallArcSegmentLength(gcsd.getSmallArcSegmentLength());
           
            if (this.controller != null) {
                applySettingsToController(this.controller);
            }

            if (this.vw != null) {
                vw.setMinArcLength(gcsd.getSmallArcThreshold());
                vw.setArcLength(gcsd.getSmallArcSegmentLength());
            }
        }
    }//GEN-LAST:event_grblConnectionSettingsMenuItemActionPerformed

    private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
        int returnVal = fileChooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                fileTextField.setText(fileChooser.getSelectedFile().getAbsolutePath());
                gcodeFile = fileChooser.getSelectedFile();
                loadFile(gcodeFile);
                       
                if (this.vw != null) {
                    vw.setGcodeFile(gcodeFile.getAbsolutePath());
                }
            } catch (FileNotFoundException ex) {
                MainWindow.displayErrorDialog(Localization.getString(
                        "mainWindow.error.openingFile") +": " + ex.getMessage());
            } catch (IOException e) {
                MainWindow.displayErrorDialog(Localization.getString(
                        "mainWindow.error.processingFile") +": " + e.getMessage());

            }
        } else {
            // Canceled file open.
        }
    }//GEN-LAST:event_browseButtonActionPerformed

    private void visualizeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_visualizeButtonActionPerformed
        // Create new object if it is null.
        if (this.vw == null) {
            this.vw = new VisualizerWindow(settings.getVisualizerWindowSettings());
           
            final MainWindow mw = this;
            vw.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent ce) {
                mw.settings.getVisualizerWindowSettings().height = ce.getComponent().getSize().height;
                mw.settings.getVisualizerWindowSettings().width = ce.getComponent().getSize().width;
            }

            @Override
            public void componentMoved(ComponentEvent ce) {
                mw.settings.getVisualizerWindowSettings().xLocation = ce.getComponent().getLocation().x;
                mw.settings.getVisualizerWindowSettings().yLocation = ce.getComponent().getLocation().y;
            }

            @Override
            public void componentShown(ComponentEvent ce) {}
            @Override
            public void componentHidden(ComponentEvent ce) {}
        });

            vw.setMinArcLength(settings.getSmallArcThreshold());
            vw.setArcLength(settings.getSmallArcSegmentLength());
            if (this.fileTextField.getText().length() > 1) {
                vw.setGcodeFile(this.fileTextField.getText());
            }
            // Add listener
            if (this.controller != null) {
                this.controller.addListener(vw);
            }
        }

        // Display the form
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                vw.setVisible(true);
            }
        });
    }//GEN-LAST:event_visualizeButtonActionPerformed

    @Override
    public void cancelButtonActionPerformed() {
        this.controller.cancelSend();

        this.updateControlsForState(ControlState.COMM_IDLE);
    }
   
    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
        cancelButtonActionPerformed();
    }//GEN-LAST:event_cancelButtonActionPerformed

    @Override
    public void pauseButtonActionPerformed() {
        // Note: Cannot cancel a send while paused because there are commands
        //       in the GRBL buffer which can't be un-sent.
        try {
            String pause = Localization.getString("mainWindow.ui.pauseButton");
            String resume = Localization.getString("mainWindow.ui.resumeButton");
           
            if (this.pauseButton.getText().equalsIgnoreCase(pause)) {
                this.controller.pauseStreaming();
                this.pauseButton.setText(resume);
                this.cancelButton.setEnabled(false);
            }
            else if (this.pauseButton.getText().equalsIgnoreCase(resume)) {
                this.controller.resumeStreaming();
                this.pauseButton.setText(pause);
                this.cancelButton.setEnabled(true);
            }
        } catch (Exception e) {
            e.printStackTrace();
            MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.pauseResume"));
        }
    }
   
    private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
      pauseButtonActionPerformed();
    }//GEN-LAST:event_pauseButtonActionPerformed

    @Override
    public void sendButtonActionPerformed(){
        ActionListener actionListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                java.awt.EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        int sent = controller.rowsSent();

                        // Early exit condition.
                        if (sent == 0) { return; }

                        long elapsedTime = controller.getSendDuration();
                        durationValueLabel.setText(Utils.formattedMillis(elapsedTime));
                        long estimate = jobEstimate;
                        if (estimate <= 0) {
                            long timePerRow = elapsedTime / sent;
                            estimate = timePerRow * controller.rowsInSend();
                        }
                        remainingTimeValueLabel.setText(Utils.formattedMillis(estimate - elapsedTime));
                    }
                });

            }
        };

        this.resetTimerLabels();

        if (timer != null){ timer.stop(); }
        timer = new Timer(1000, actionListener);

        // Note: there is a divide by zero error in the timer because it uses
        //       the rowsValueLabel that was just reset.

        try {
            // This will throw an exception and prevent that other stuff from
            // happening (clearing the table before its ready for clearing.
            this.controller.isReadyToStreamFile();

            this.updateControlsForState(ControlState.COMM_SENDING);

            // Mark the position in the table where the commands will begin.
            //commandTable.setOffset();

            if (G91Mode) {
                this.controller.preprocessAndAppendGcodeCommand("G90");
            }

            this.controller.appendGcodeCommands(processedCommandLines, this.gcodeFile);

            this.resetSentRowLabels(this.controller.rowsInQueue());
            timer.start();
            this.controller.beginStreaming();
        } catch (Exception e) {
            timer.stop();
            this.updateControlsForState(ControlState.COMM_IDLE);
            e.printStackTrace();
            MainWindow.displayErrorDialog(
                    Localization.getString("mainWindow.error.startingStream") + ": "+e.getMessage());
        }
    }
   
    private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendButtonActionPerformed
      sendButtonActionPerformed();
    }//GEN-LAST:event_sendButtonActionPerformed

    private void grblFirmwareSettingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_grblFirmwareSettingsMenuItemActionPerformed
        try {
            if (this.controller == null) {
                MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.noFirmware"));
            } else if (this.controller instanceof GrblController) {
                    GrblFirmwareSettingsDialog gfsd = new GrblFirmwareSettingsDialog(this, true, (GrblController)this.controller);
                    gfsd.setVisible(true);
            } else {
                MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.notGrbl"));
            }
        } catch (Exception ex) {
                MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_grblFirmwareSettingsMenuItemActionPerformed

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
        int returnVal = fileChooser.showSaveDialog(this);
                //fileChooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                File newFile = fileChooser.getSelectedFile();
                AbstractController control = FirmwareUtils.getControllerFor(FirmwareUtils.GRBL);
                applySettingsToController(control);
                control.appendGcodeCommands(this.processedCommandLines, this.gcodeFile);
                control.saveToFile(newFile);
            } catch (FileNotFoundException ex) {
                MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.openingFile")
                        + ": " + ex.getMessage());
            } catch (IOException e) {
                MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.processingFile")
                        + ": "+e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
                MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.duringSave") +
                        ": " + e.getMessage());
            }
        }   
    }//GEN-LAST:event_saveButtonActionPerformed

        private void startPendantServerButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startPendantServerButtonActionPerformed
      this.pendantUI = new PendantUI(this);
      this.pendantUI.start();
      this.startPendantServerButton.setEnabled(false);
      this.stopPendantServerButton.setEnabled(true);
           
            if (this.controller != null) {
                this.controller.addListener(pendantUI);
            }
        }//GEN-LAST:event_startPendantServerButtonActionPerformed

        private void stopPendantServerButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopPendantServerButtonActionPerformed
      this.pendantUI.stop();
      this.startPendantServerButton.setEnabled(true);
      this.stopPendantServerButton.setEnabled(false);
        }//GEN-LAST:event_stopPendantServerButtonActionPerformed

    private void customGcodeText1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeText1ActionPerformed
        this.settings.setCustomGcode1(this.customGcodeText1.getText());
    }//GEN-LAST:event_customGcodeText1ActionPerformed

    private void customGcodeButton5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeButton5ActionPerformed
        executeCustomGcode(this.customGcodeText5.getText());
    }//GEN-LAST:event_customGcodeButton5ActionPerformed

    private void customGcodeButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeButton1ActionPerformed
        executeCustomGcode(this.customGcodeText1.getText());
    }//GEN-LAST:event_customGcodeButton1ActionPerformed

    private void customGcodeButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeButton2ActionPerformed
        executeCustomGcode(this.customGcodeText2.getText());
    }//GEN-LAST:event_customGcodeButton2ActionPerformed

    private void customGcodeButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeButton3ActionPerformed
        executeCustomGcode(this.customGcodeText3.getText());
    }//GEN-LAST:event_customGcodeButton3ActionPerformed

    private void customGcodeButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeButton4ActionPerformed
        executeCustomGcode(this.customGcodeText4.getText());
    }//GEN-LAST:event_customGcodeButton4ActionPerformed

    private void resetZCoordinateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetZCoordinateButtonActionPerformed
        resetZCoordinateButtonActionPerformed();
    }//GEN-LAST:event_resetZCoordinateButtonActionPerformed

    private void resetYCoordinateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetYCoordinateButtonActionPerformed
        resetYCoordinateButtonActionPerformed();
    }//GEN-LAST:event_resetYCoordinateButtonActionPerformed

    private void resetXCoordinateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetXCoordinateButtonActionPerformed
        resetXCoordinateButtonActionPerformed();
    }//GEN-LAST:event_resetXCoordinateButtonActionPerformed

    private void requestStateInformationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_requestStateInformationActionPerformed
        try {
            this.controller.viewParserState();
        } catch (Exception ex) {
            ex.printStackTrace();
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_requestStateInformationActionPerformed

    private void softResetMachineControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_softResetMachineControlActionPerformed
        try {
            this.controller.issueSoftReset();
        } catch (Exception ex) {
            ex.printStackTrace();
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_softResetMachineControlActionPerformed

    private void helpButtonMachineControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpButtonMachineControlActionPerformed
        StringBuilder message = new StringBuilder()
        .append(Localization.getString("mainWindow.resetZero")).append("\n")
        .append(Localization.getString("mainWindow.returnToZero")).append("\n")
        .append(Localization.getString("mainWindow.softReset")).append("\n")
        .append(Localization.getString("mainWindow.homing")).append("\n")
        .append(Localization.getString("mainWindow.alarmLock")).append("\n")
        .append(Localization.getString("mainWindow.checkMode")).append("\n")
        .append(Localization.getString("mainWindow.getState")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyboard")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyX")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyY")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyZ")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyPlusMinus")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyDivMul")).append("\n")
        .append(Localization.getString("mainWindow.helpKeyZero")).append("\n")
        ;

        JOptionPane.showMessageDialog(new JFrame(),
            message,
            Localization.getString("mainWindow.helpDialog"),
            JOptionPane.INFORMATION_MESSAGE);
    }//GEN-LAST:event_helpButtonMachineControlActionPerformed

    private void toggleCheckModeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggleCheckModeActionPerformed
        try {
            this.controller.toggleCheckMode();
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_toggleCheckModeActionPerformed

    private void killAlarmLockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_killAlarmLockActionPerformed
        try {
            this.controller.killAlarmLock();
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_killAlarmLockActionPerformed

    private void performHomingCycleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_performHomingCycleButtonActionPerformed
        try {
            this.controller.performHomingCycle();
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }//GEN-LAST:event_performHomingCycleButtonActionPerformed

    private void yPlusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_yPlusButtonActionPerformed
        this.adjustManualLocation(0, 1, 0);
    }//GEN-LAST:event_yPlusButtonActionPerformed

    private void zPlusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zPlusButtonActionPerformed
        this.adjustManualLocation(0, 0, 1);
    }//GEN-LAST:event_zPlusButtonActionPerformed

    private void xMinusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xMinusButtonActionPerformed
        this.adjustManualLocation(-1, 0, 0);
    }//GEN-LAST:event_xMinusButtonActionPerformed

    private void xPlusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xPlusButtonActionPerformed
        this.adjustManualLocation(1, 0, 0);
    }//GEN-LAST:event_xPlusButtonActionPerformed

    private void yMinusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_yMinusButtonActionPerformed
        this.adjustManualLocation(0, -1, 0);
    }//GEN-LAST:event_yMinusButtonActionPerformed

    private void zMinusButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zMinusButtonActionPerformed
        this.adjustManualLocation(0, 0, -1);
    }//GEN-LAST:event_zMinusButtonActionPerformed

    private void stepSizeSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_stepSizeSpinnerStateChanged

    }//GEN-LAST:event_stepSizeSpinnerStateChanged

    private void returnToZeroButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_returnToZeroButtonActionPerformed
        returnToZeroButtonActionPerformed();
    }//GEN-LAST:event_returnToZeroButtonActionPerformed

    private void resetCoordinatesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetCoordinatesButtonActionPerformed
        resetCoordinatesButtonActionPerformed();
    }//GEN-LAST:event_resetCoordinatesButtonActionPerformed

    private void customGcodeText2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeText2ActionPerformed
        this.settings.setCustomGcode2(this.customGcodeText2.getText());
    }//GEN-LAST:event_customGcodeText2ActionPerformed

    private void customGcodeText3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeText3ActionPerformed
        this.settings.setCustomGcode3(this.customGcodeText3.getText());
    }//GEN-LAST:event_customGcodeText3ActionPerformed

    private void customGcodeText4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeText4ActionPerformed
        this.settings.setCustomGcode4(this.customGcodeText4.getText());
    }//GEN-LAST:event_customGcodeText4ActionPerformed

    private void customGcodeText5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customGcodeText5ActionPerformed
        this.settings.setCustomGcode5(this.customGcodeText5.getText());
    }//GEN-LAST:event_customGcodeText5ActionPerformed

    private void executeCustomGcode(String str)
    {
        str = str.replaceAll("(\\r\\n|\\n\\r|\\r|\\n)", "");
        final String[] parts = str.split(";");
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    for (String cmd : parts)
                    {
                        controller.queueStringForComm(cmd);
                    }
                } catch (Exception ex) {
                    displayErrorDialog(ex.getMessage());
                }
            }
        });
       
        for (String cmd : parts)
        {
            this.manualCommandHistory.add(cmd);
            this.commandNum = -1;
        }
    }
   
    /**
     * @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(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
       
         /* Create the form */
        final MainWindow mw = new MainWindow();

        /* Load the stored settings or generate defaults */
        mw.settings = SettingsFactory.loadSettings();
       
       
        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();

        /* Apply the settings to the MainWindow bofore showing it */
        mw.arrowMovementEnabled.setSelected(mw.settings.isManualModeEnabled());
        mw.stepSizeSpinner.setValue(mw.settings.getManualModeStepSize());
        mw.fileChooser = new JFileChooser(mw.settings.getFileName());
        mw.commPortComboBox.setSelectedItem(mw.settings.getPort());
        mw.baudrateSelectionComboBox.setSelectedItem(mw.settings.getPortRate());
        mw.scrollWindowCheckBox.setSelected(mw.settings.isScrollWindowEnabled());
        mw.showVerboseOutputCheckBox.setSelected(mw.settings.isVerboseOutputEnabled());
        mw.firmwareComboBox.setSelectedItem(mw.settings.getFirmwareVersion());
        mw.customGcodeText1.setText(mw.settings.getCustomGcode1());
        mw.customGcodeText2.setText(mw.settings.getCustomGcode2());
        mw.customGcodeText3.setText(mw.settings.getCustomGcode3());
        mw.customGcodeText4.setText(mw.settings.getCustomGcode4());
        mw.customGcodeText5.setText(mw.settings.getCustomGcode5());
        mw.setSize(mw.settings.getMainWindowSettings().width, mw.settings.getMainWindowSettings().height);
        mw.setLocation(mw.settings.getMainWindowSettings().xLocation, mw.settings.getMainWindowSettings().yLocation);
//        mw.setSize(java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().width, java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().width);
       
        mw.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent ce) {
                mw.settings.getMainWindowSettings().height = ce.getComponent().getSize().height;
                mw.settings.getMainWindowSettings().width = ce.getComponent().getSize().width;
            }

            @Override
            public void componentMoved(ComponentEvent ce) {
                mw.settings.getMainWindowSettings().xLocation = ce.getComponent().getLocation().x;
                mw.settings.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);
            }
        });
       
        mw.initFileChooser();
       
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                if (mw.fileChooser.getSelectedFile() != null ) {
                    mw.settings.setFileName(mw.fileChooser.getSelectedFile().getAbsolutePath());
                }
               
                mw.settings.setManualModeStepSize(mw.getStepSize());
                mw.settings.setManualModeEnabled(mw.arrowMovementEnabled.isSelected());
                mw.settings.setPort(mw.commPortComboBox.getSelectedItem().toString());
                mw.settings.setPortRate(mw.baudrateSelectionComboBox.getSelectedItem().toString());
                mw.settings.setScrollWindowEnabled(mw.scrollWindowCheckBox.isSelected());
                mw.settings.setVerboseOutputEnabled(mw.showVerboseOutputCheckBox.isSelected());
                mw.settings.setFirmwareVersion(mw.firmwareComboBox.getSelectedItem().toString());
                SettingsFactory.saveSettings(mw.settings);
               
                if(mw.pendantUI!=null){
                  mw.pendantUI.stop();
                }
            }
        });
    }
   
    /**
     * FileChooser has to be initialized after JFrame is opened, otherwise the settings will not be applied.
     */
    private void initFileChooser() {
        //Setup the file filter for gcode files.
        GcodeFileTypeFilter filter = new GcodeFileTypeFilter();
       
        // Setup file browser with the last path used.
        this.fileChooser = new JFileChooser(settings.getFileName());
        this.fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        this.fileChooser.setFileHidingEnabled(true);
        this.fileChooser.addChoosableFileFilter(filter);
        this.fileChooser.setAcceptAllFileFilterUsed(true);
        this.fileChooser.setFileFilter(filter);
    }
       
    private void initProgram() {
        this.setLocalLabels();
        this.loadPortSelector();
        this.checkScrollWindow();
        this.loadFirmwareSelector();
        this.setTitle(Localization.getString("title") + " ("
                + Localization.getString("version") + " " + VERSION + ")");
       
        // Command History
        this.manualCommandHistory = new ArrayList<String>();
        this.commandTextField.addKeyListener(this);
       
        // Add keyboard listener for manual controls.
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addKeyEventDispatcher(new KeyEventDispatcher() {
                @Override
                public boolean dispatchKeyEvent(KeyEvent e) {
                    // Check context.
                    if (((arrowMovementEnabled.isSelected()) &&
                            e.getID() == KeyEvent.KEY_PRESSED) &&
                            xPlusButton.isEnabled()) {
                        switch (e.getKeyCode()) {
                            case KeyEvent.VK_RIGHT:
                            case KeyEvent.VK_KP_RIGHT:
                            case KeyEvent.VK_NUMPAD6:
                                xPlusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_LEFT:
                            case KeyEvent.VK_KP_LEFT:
                            case KeyEvent.VK_NUMPAD4:
                                xMinusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_UP:
                            case KeyEvent.VK_KP_UP:
                            case KeyEvent.VK_NUMPAD8:
                                yPlusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_DOWN:
                            case KeyEvent.VK_KP_DOWN:
                            case KeyEvent.VK_NUMPAD2:                                                                                                                       
                                yMinusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_PAGE_UP:
                            case KeyEvent.VK_NUMPAD9:
                                zPlusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_PAGE_DOWN:
                            case KeyEvent.VK_NUMPAD3:
                                zMinusButtonActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_ADD:
                                increaseStepActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_SUBTRACT:
                                decreaseStepActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_DIVIDE:
                                divideStepActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_MULTIPLY:
                                multiplyStepActionPerformed(null);
                                e.consume();
                                return true;
                            case KeyEvent.VK_INSERT:
                            case KeyEvent.VK_NUMPAD0:
                                resetCoordinatesButtonActionPerformed(null);
                                e.consume();
                                return true;
                        }
                    }
                   
                    return false;
                }
            });
    }

    private double getStepSize() {
        BigDecimal bd = new BigDecimal(this.stepSizeSpinner.getValue().toString()).setScale(2, RoundingMode.HALF_EVEN);
        return bd.doubleValue();
        //return Double.parseDouble( this.stepSizeSpinner.getValue().toString() );
    }

    private void setStepSize(double val) {
        BigDecimal bd = new BigDecimal(val).setScale(2, RoundingMode.HALF_EVEN);
        val = bd.doubleValue();
        this.stepSizeSpinner.setValue(val);
    }

    /**
     * Sends a G91 command in some combination of x, y, and z directions with a
     * step size of stepDirection.
     *
     * Direction is specified by the direction param being positive or negative.
     */
    public void adjustManualLocation(int dirX, int dirY, int dirZ, double stepSize) {
       
        // Don't send empty commands.
        if ((dirX == 0) && (dirY == 0) && (dirZ == 0)) {
            return;
        }

        // Format step size from spinner.
        String formattedStepSize = formatter.format(stepSize);

        // Build G91 command.
        StringBuilder command = new StringBuilder("G91 G0 ");
       
        if (dirX != 0) {
            command.append(" X");
            if (dirX < 0) {
                command.append('-');
            }
            command.append(formattedStepSize);
        } if (dirY != 0) {
            command.append(" Y");
            if (dirY < 0) {
                command.append('-');
            }
            command.append(formattedStepSize);
        } if (dirZ != 0) {
            command.append(" Z");
            if (dirZ < 0) {
                command.append('-');
            }
            command.append(formattedStepSize);
        }

        try {
            this.controller.queueStringForComm(command.toString());
            G91Mode = true;
        } catch (Exception ex) {
            MainWindow.displayErrorDialog(ex.getMessage());
        }
    }
   
    /**
     * Sends a G91 command in some combination of x, y, and z directions with a
     * step size of stepDirection.
     *
     * Direction is specified by the direction param being positive or negative.
     */
    public void adjustManualLocation(int dirX, int dirY, int dirZ) {
      adjustManualLocation(dirX, dirY, dirZ, this.getStepSize());
    }
   
    private void setStatusColorForState(String state) {
        if (settings.isDisplayStateColor()) {
            java.awt.Color color = null; // default to a transparent background.
            if (state.equals(Localization.getString("mainWindow.status.alarm"))) {
                color = Color.RED;
            } else if (state.equals(Localization.getString("mainWindow.status.hold"))) {
                color = Color.YELLOW;
            } else if (state.equals(Localization.getString("mainWindow.status.queue"))) {
                color = Color.YELLOW;
            } else if (state.equals(Localization.getString("mainWindow.status.run"))) {
                color = Color.GREEN;
            }

            this.activeStateLabel.setBackground(color);
            this.activeStateValueLabel.setBackground(color);
        } else {
            this.activeStateLabel.setBackground(null);
            this.activeStateValueLabel.setBackground(null);
        }
    }
   
    private ControlState lastControlState = ControlState.COMM_DISCONNECTED;
   
    private void updateControlsForState(ControlState state) {
       
        switch (state) {
            case FILE_SELECTED:
                this.saveButton.setEnabled(true);
                this.visualizeButton.setEnabled(true);
                this.updateFileControls(this.controller != null && this.controller.isCommOpen());
                break;
            case COMM_DISCONNECTED:
                this.updateConnectionControls(false);
                this.updateManualControls(false);
                this.updateWorkflowControls(false);
                this.updateCustomGcodeControls(false);
                this.updateFileControls(false);
                this.updateControlsStopSending();
                this.setStatusColorForState("");
                break;
            case COMM_IDLE:
                this.updateConnectionControls(true);
                this.updateManualControls(true);
                this.updateWorkflowControls(true);
                this.updateCustomGcodeControls(true);
                this.updateControlsStopSending();
                break;
            case COMM_SENDING:
                // Command tab
                this.commandTextField.setEnabled(false);

                // File tab
                this.sendButton.setEnabled(false);
                this.pauseButton.setEnabled(true);
                this.cancelButton.setEnabled(true);
                this.pauseButton.setText(Localization.getString("mainWindow.ui.pauseButton"));

                // Workflow tab
                this.updateWorkflowControls(false);
                this.updateCustomGcodeControls(false);
                // Jogging commands
                this.updateManualControls(false);
       
                break;
            case COMM_SENDING_PAUSED:
                this.pauseButton.setText(Localization.getString("mainWindow.ui.resumeButton"));
                break;
            default:
               
        }
       
        lastControlState = state;
    }
   
    /**
     * Enable/disable connection frame based on connection state.
     */
    private void updateConnectionControls(boolean isOpen) {

        this.commPortComboBox.setEnabled(!isOpen);
        this.baudrateSelectionComboBox.setEnabled(!isOpen);
        this.refreshButton.setEnabled(!isOpen);
        this.commandTextField.setEnabled(isOpen);

        if (isOpen) {
            this.opencloseButton.setText(Localization.getString("close"));
        } else {
            this.opencloseButton.setText(Localization.getString("open"));
        }
    }
   
    /**
     * Enable/disable file frame based on connection state.
     */
    private void updateFileControls(boolean enabled) {
        this.sendButton.setEnabled(enabled && this.gcodeFile != null);
        //browse always enabled.
        //this.browseButton.setEnabled(enabled);
        this.fileTextField.setEnabled(enabled);

        if (!enabled) {
            updateControlsStopSending();
        }
    }
   
    private void updateControlsStopSending() {
        if (this.timer != null && this.timer.isRunning()) {
            // Stop the timer
            this.timer.stop();
        }
       
        // In case transitioning from file sending or file send paused.
        this.pauseButton.setText(Localization.getString("mainWindow.ui.pauseButton"));
        this.pauseButton.setEnabled(false);
        this.cancelButton.setEnabled(false);
    }
   
    /**
     * Enable/disable jogging controls.
     */
    private void updateManualControls(boolean enabled) {
        this.arrowMovementEnabled.setEnabled(enabled);

        this.xMinusButton.setEnabled(enabled);
        this.xPlusButton.setEnabled(enabled);
        this.yMinusButton.setEnabled(enabled);
        this.yPlusButton.setEnabled(enabled);
        this.zMinusButton.setEnabled(enabled);
        this.zPlusButton.setEnabled(enabled);
        this.stepSizeLabel.setEnabled(enabled);
        this.stepSizeSpinner.setEnabled(enabled);
    }
   
    private void updateWorkflowControls(boolean enabled) {
        this.resetCoordinatesButton.setEnabled(enabled);
        this.resetXButton.setEnabled(enabled);
        this.resetYButton.setEnabled(enabled);
        this.resetZButton.setEnabled(enabled);
        this.returnToZeroButton.setEnabled(enabled);
        this.performHomingCycleButton.setEnabled(enabled);
        this.softResetMachineControl.setEnabled(enabled);
        this.killAlarmLock.setEnabled(enabled);
        this.toggleCheckMode.setEnabled(enabled);
        this.requestStateInformation.setEnabled(enabled);
    }
   
    private void updateCustomGcodeControls(boolean enabled) {
        this.customGcodeButton1.setEnabled(enabled);   
        this.customGcodeButton2.setEnabled(enabled);  
        this.customGcodeButton3.setEnabled(enabled);
        this.customGcodeButton4.setEnabled(enabled);
        this.customGcodeButton5.setEnabled(enabled);       
        this.customGcodeText1.setEnabled(enabled);
        this.customGcodeText2.setEnabled(enabled);
        this.customGcodeText3.setEnabled(enabled);
        this.customGcodeText4.setEnabled(enabled);
        this.customGcodeText5.setEnabled(enabled);
    }

    private void resetTimerLabels() {
        // Reset labels
        this.durationValueLabel.setText("00:00:00");
        if (this.jobEstimate < 0) {
            this.remainingTimeValueLabel.setText("estimating...");
        } else if (this.jobEstimate == 0) {
            this.remainingTimeValueLabel.setText("--:--:--");
        } else {
            this.remainingTimeValueLabel.setText(Utils.formattedMillis(this.jobEstimate));
        }
    }

    private void resetSentRowLabels(Integer numRows) {
        // Reset labels
        String totalRows =  numRows.toString();
        resetTimerLabels();
        this.sentRowsValueLabel.setText("0");
        this.remainingRowsValueLabel.setText(totalRows);
        this.rowsValueLabel.setText(totalRows);
    }
   
    /**
     * Updates all text labels in the GUI with localized labels.
     */
    private void setLocalLabels() {
        this.arrowMovementEnabled.setText(Localization.getString("mainWindow.swing.arrowMovementEnabled"));
        this.baudLabel.setText(Localization.getString("mainWindow.swing.baudLabel"));
        this.browseButton.setText(Localization.getString("mainWindow.swing.browseButton"));
        this.cancelButton.setText(Localization.getString("mainWindow.swing.cancelButton"));
        this.commandLabel.setText(Localization.getString("mainWindow.swing.commandLabel"));
        this.connectionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
                Localization.getString("mainWindow.swing.connectionPanel")));
        this.controlContextTabbedPane.setTitleAt(0, Localization.getString("mainWindow.swing.controlContextTabbedPane.commands"));
        this.controlContextTabbedPane.setTitleAt(1, Localization.getString("mainWindow.swing.controlContextTabbedPane.fileMode"));
        this.controlContextTabbedPane.setTitleAt(2, Localization.getString("mainWindow.swing.controlContextTabbedPane.machineControl"));
        this.controlContextTabbedPane.setTitleAt(3, Localization.getString("mainWindow.swing.controlContextTabbedPane.macros"));
        this.durationLabel.setText(Localization.getString("mainWindow.swing.durationLabel"));
        this.fileLabel.setText(Localization.getString("mainWindow.swing.fileLabel"));
        this.firmwareLabel.setText(Localization.getString("mainWindow.swing.firmwareLabel"));
        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.helpButtonMachineControl.setText(Localization.getString("help"));
        this.settingsMenu.setText(Localization.getString("mainWindow.swing.settingsMenu"));
        this.statusPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
                Localization.getString("mainWindow.swing.statusPanel")));
        this.bottomTabbedPane.setTitleAt(0, Localization.getString("mainWindow.swing.bottomTabbedPane.console"));
        this.bottomTabbedPane.setTitleAt(1, Localization.getString("mainWindow.swing.bottomTabbedPane.table"));
        this.latestCommentLabel.setText(Localization.getString("mainWindow.swing.latestCommentLabel"));
        this.machinePosition.setText(Localization.getString("mainWindow.swing.machinePosition"));
        this.opencloseButton.setText(Localization.getString("mainWindow.swing.opencloseButton"));
        this.pauseButton.setText(Localization.getString("mainWindow.swing.pauseButton"));
        this.portLabel.setText(Localization.getString("mainWindow.swing.portLabel"));
        this.remainingRowsLabel.setText(Localization.getString("mainWindow.swing.remainingRowsLabel"));
        this.remainingTimeLabel.setText(Localization.getString("mainWindow.swing.remainingTimeLabel"));
        this.resetCoordinatesButton.setText(Localization.getString("mainWindow.swing.resetCoordinatesButton"));
        this.returnToZeroButton.setText(Localization.getString("mainWindow.swing.returnToZeroButton"));
        this.rowsLabel.setText(Localization.getString("mainWindow.swing.rowsLabel"));
        this.saveButton.setText(Localization.getString("save"));
        this.scrollWindowCheckBox.setText(Localization.getString("mainWindow.swing.scrollWindowCheckBox"));
        this.sendButton.setText(Localization.getString("mainWindow.swing.sendButton"));
        this.sentRowsLabel.setText(Localization.getString("mainWindow.swing.sentRowsLabel"));
        this.showVerboseOutputCheckBox.setText(Localization.getString("mainWindow.swing.showVerboseOutputCheckBox"));
        this.softResetMachineControl.setText(Localization.getString("mainWindow.swing.softResetMachineControl"));
        this.stepSizeLabel.setText(Localization.getString("mainWindow.swing.stepSizeLabel"));
        this.visualizeButton.setText(Localization.getString("mainWindow.swing.visualizeButton"));
        this.workPositionLabel.setText(Localization.getString("mainWindow.swing.workPositionLabel"));
        this.macroInstructions.setText(Localization.getString("mainWindow.swing.macroInstructions")+"yep");
    }
   
    // Scans for comm ports and puts them in the comm port combo box.
    private void loadPortSelector() {
        commPortComboBox.removeAllItems();
       
        List<CommPortIdentifier> portList = CommUtils.getSerialPortList();

        if (portList.size() < 1) {
            MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.noSerialPort"));
        } else {
            // Sort?
            //java.util.Collections.sort(portList);

            java.util.Iterator<CommPortIdentifier> portIter = portList.iterator();

            while ( portIter.hasNext() ) {
                CommPortIdentifier portIdentifier = portIter.next();
                commPortComboBox.addItem(portIdentifier.getName());
            }

            commPortComboBox.setSelectedIndex(0);
        }
    }
   
    private void loadFirmwareSelector() {
        firmwareComboBox.removeAllItems();
        List<String> firmwareList = FirmwareUtils.getFirmwareList();
       
        if (firmwareList.size() < 1) {
            MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.noFirmware"));
        } else {
            java.util.Iterator<String> iter = firmwareList.iterator();
            while ( iter.hasNext() ) {
                firmwareComboBox.addItem(iter.next());
            }
        }
    }
   
    private void loadFile(java.io.File file) throws FileNotFoundException, IOException {
        this.jobEstimate = 0L;
        this.gcodeFile = file;
        FileReader fr = new FileReader(file);
        Charset cs = Charset.forName(fr.getEncoding());
        fr.close();
        List<String> lines = Files.readAllLines(file.toPath(), cs);
        if (this.controller != null && this.controller.isCommOpen())  {
            this.processedCommandLines = this.controller.preprocess(lines);
            this.jobEstimate = -1L;
            this.resetSentRowLabels(this.processedCommandLines.size());
            Thread estimateThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    jobEstimate = controller.getJobLengthEstimate(processedCommandLines);
                    resetSentRowLabels(processedCommandLines.size());
                    updateControlsForState(ControlState.FILE_SELECTED);
                }
            });
            estimateThread.start();

        } else {
            this.resetSentRowLabels(lines.size());
            updateControlsForState(ControlState.FILE_SELECTED);
        }

        if (this.vw != null) {
            vw.setGcodeFile(file.getAbsolutePath());
        }
    }

    private void applySettingsToController(AbstractController controller) {
        // Apply settings settings to controller.
        if (settings.isOverrideSpeedSelected()) {
            double value = settings.getOverrideSpeedValue();
            controller.setSpeedOverride(value);
        } else {
            controller.setSpeedOverride(-1);
        }

        try {
            controller.setMaxCommandLength(settings.getMaxCommandLength());
            controller.setTruncateDecimalLength(settings.getTruncateDecimalLength());
            controller.setSingleStepMode(settings.isSingleStepMode());
            controller.setStatusUpdatesEnabled(settings.isStatusUpdatesEnabled());
            controller.setStatusUpdateRate(settings.getStatusUpdateRate());
            controller.setRemoveAllWhitespace(settings.isRemoveAllWhitespace());
            controller.setConvertArcsToLines(settings.isConvertArcsToLines());
            controller.setSmallArcThreshold(settings.getSmallArcThreshold());
            controller.setSmallArcSegmentLength(settings.getSmallArcSegmentLength());
        } catch (Exception ex) {

            StringBuilder message = new StringBuilder()
                    .append(Localization.getString("mainWindow.error.firmwareSetting"))
                    .append(": \n    ")
                    .append(Localization.getString("firmware.feature.maxCommandLength")).append("\n    ")
                    .append(Localization.getString("firmware.feature.truncateDecimal")).append("\n    ")
                    .append(Localization.getString("firmware.feature.singleStep")).append("\n    ")
                    .append(Localization.getString("firmware.feature.removeWhitespace")).append("\n    ")
                    .append(Localization.getString("firmware.feature.linesToArc")).append("\n    ")
                    .append(Localization.getString("firmware.feature.statusUpdates")).append("\n    ")
                    .append(Localization.getString("firmware.feature.statusUpdateRate"));
           
            MainWindow.displayErrorDialog(message
                    + "\n\n" + ex.getMessage());
        }
    }
   
    private void checkScrollWindow() {
        // Console output.
        DefaultCaret caret = (DefaultCaret)consoleTextArea.getCaret();
        if (scrollWindowCheckBox.isSelected()) {
          caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
          consoleTextArea.setCaretPosition(consoleTextArea.getDocument().getLength());
        } else {
            caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
        }
       
        // Command table.
        this.commandTable.setAutoWindowScroll(scrollWindowCheckBox.isSelected());
    }
   
    private String getNewline() {
        return "\r\n";
       
        /*
        if (lineBreakNR.isSelected())
            return "\n\r";
        else if (lineBreakRN.isSelected())
            return "\r\n";
        else if (lineBreakN.isSelected())
            return "\n";
        else
            return "wtfbbq";
        */
    }

    private boolean openCommConnection() {
        boolean connected = false;
        try {
            this.clearTable();
            this.sentRowsValueLabel.setText("0");
            this.sentRows = 0;

            String port = commPortComboBox.getSelectedItem().toString();
            int portRate = Integer.parseInt(baudrateSelectionComboBox.getSelectedItem().toString());
            
            connected = controller.openCommPort(port, portRate);

        } catch (PortInUseException e) {
           
           
            //Localization.getString("")
            StringBuilder message = new StringBuilder()
                    .append(Localization.getString("mainWindow.error.rxtx"))
                    .append("(")
                    .append(e.getClass().getName())
                    .append("): ")
                    .append(e.getMessage()).append("\n\n")
           
                    .append(Localization.getString("mainWindow.error.rxtxMac1"))
                    .append(String.format(Localization.getString("mainWindow.error.rxtxMac2"), "\"/var/lock\""))
                    .append("\n     sudo mkdir /var/lock")
                    .append("\n     sudo chmod 777 /var/lock");
            MainWindow.displayErrorDialog(message.toString());
        }catch (Exception e) {
            e.printStackTrace();
            MainWindow.displayErrorDialog(Localization.getString("mainWindow.error.connection")
                    + " ("+ e.getClass().getName() + "): "+e.getMessage());
        }
        return connected;
    }
   
    private void closeCommConnection() {
        this.controller.closeCommPort();
        this.controller = null;
    }
   
    void clearTable() {
        this.commandTable.clear();
    }
       
    private static void displayErrorDialog(String errorMessage) {
        JOptionPane.showMessageDialog(new JFrame(), errorMessage,
                Localization.getString("error"), JOptionPane.ERROR_MESSAGE);
    }
   
    /** SerialCommunicatorListener implementation.
     */
   
    @Override
    public void fileStreamComplete(String filename, boolean success) {
        // Stop the timer
        this.timer.stop();
        remainingTimeValueLabel.setText(Utils.formattedMillis(0));
        remainingRowsValueLabel.setText("" + controller.rowsInQueue());

        this.updateControlsForState(ControlState.COMM_IDLE);

        if (success) {
            JOptionPane.showMessageDialog(new JFrame(),
                    Localization.getString("mainWindow.ui.jobComplete") + " " + this.durationValueLabel.getText(),
                    Localization.getString("success"), JOptionPane.INFORMATION_MESSAGE);
        } else {
            displayErrorDialog(Localization.getString("mainWindow.error.jobComplete"));
        }
    }
   
    @Override
    public void commandQueued(GcodeCommand command) {
        this.commandTable.addRow(command);
    }
    
    @Override
    public void commandSent(final GcodeCommand command) {
        if (this.controller.isStreamingFile()) {
            // Update # rows sent label
            this.sentRows++;
        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                //sentRowsValueLabel.setText(""+sentRows);
                sentRowsValueLabel.setText(""+controller.rowsSent());
               
                // sent
                commandTable.updateRow(command);
            }});
    }
   
    @Override
    public void commandComment(String comment) {
        latestCommentValueLabel.setText(comment);
    }
   
    @Override
    public void commandComplete(final GcodeCommand command) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                commandTable.updateRow(command);

                if (controller.isStreamingFile()) {
                    // decrement remaining rows
                    int remaining = Integer.parseInt(remainingRowsValueLabel.getText());
                    if (remaining > 0) {
                        remaining--;
                        remainingRowsValueLabel.setText("" + remaining);
                    }
                    if (vw != null) {
                        vw.setCompletedCommandNumber(controller.rowsSent());
                    }
                }
            }});
    }

    // TODO: Change verbose into an enum to toggle regular/verbose/error.
    @Override
    public void messageForConsole(final String msg, final Boolean verbose) {
        final javax.swing.JTextArea consoleTextArea = this.consoleTextArea;
        final javax.swing.JCheckBox showVerboseOutputCheckBox = this.showVerboseOutputCheckBox;
        final javax.swing.JCheckBox scrollWindowCheckBox = this.scrollWindowCheckBox;

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (!verbose || showVerboseOutputCheckBox.isSelected()) {
                    String verboseS = "[" + Localization.getString("verbose") + "]";
                    consoleTextArea.append((verbose ? verboseS : "") + msg);

                    if (consoleTextArea.isVisible() &&
                            scrollWindowCheckBox.isEnabled()) {
                        consoleTextArea.setCaretPosition(consoleTextArea.getDocument().getLength());
                    }
                }
            }
        });
    }
   
    @Override
    public void statusStringListener(String state, Point3d machineCoord, Point3d workCoord) {
        this.activeStateValueLabel.setText( state );
        this.setStatusColorForState( state );
       
        if (machineCoord != null) {
            this.machinePositionXValueLabel.setText( formatter.format(machineCoord.x) + "" );
            this.machinePositionYValueLabel.setText( formatter.format(machineCoord.y) + "" );
            this.machinePositionZValueLabel.setText( formatter.format(machineCoord.z) + "" );
        }
       
        if (workCoord != null) {
            this.workPositionXValueLabel.setText( formatter.format(workCoord.x) + "" );
            this.workPositionYValueLabel.setText( formatter.format(workCoord.y) + "" );
            this.workPositionZValueLabel.setText( formatter.format(workCoord.z) + "" );
        }
    }
   
    @Override
    public void postProcessData(int numRows) {
    }

    public Settings getSettings() {
        return settings;
    }

    public AbstractController getController() {
        return controller;
    }

    @Override
    public void updateSystemState(SystemStateBean systemStateBean) {
        systemStateBean.setFileName(fileTextField.getText());
        systemStateBean.setLatestComment(latestCommentValueLabel.getText());
        systemStateBean.setActiveState(activeStateValueLabel.getText());
        systemStateBean.setControlState(lastControlState);
        systemStateBean.setDuration(durationValueLabel.getText());
        systemStateBean.setEstimatedTimeRemaining(remainingTimeValueLabel.getText());
        systemStateBean.setMachineX(machinePositionXValueLabel.getText());
        systemStateBean.setMachineY(machinePositionYValueLabel.getText());
        systemStateBean.setMachineZ(machinePositionZValueLabel.getText());
        systemStateBean.setRemainingRows(remainingRowsValueLabel.getText());
        systemStateBean.setRowsInFile(rowsValueLabel.getText());
        systemStateBean.setSentRows(sentRowsValueLabel.getText());
        systemStateBean.setWorkX(workPositionXValueLabel.getText());
        systemStateBean.setWorkY(workPositionYValueLabel.getText());
        systemStateBean.setWorkZ(workPositionZValueLabel.getText());
        systemStateBean.setSendButtonText(sendButton.getText());
        systemStateBean.setSendButtonEnabled(sendButton.isEnabled());
        systemStateBean.setPauseResumeButtonEnabled(pauseButton.isEnabled());
        systemStateBean.setPauseResumeButtonText(pauseButton.getText());
        systemStateBean.setCancelButtonText(cancelButton.getText());
        systemStateBean.setCancelButtonEnabled(cancelButton.isEnabled());
    }
   
    // My Variables
    private javax.swing.JFileChooser fileChooser;
    private java.io.File gcodeFile;
    private List<String> processedCommandLines;

    // TODO: Move command history box into a self contained object.
    // This is for the command history box.
    private int commandNum = -1;
    private List<String> manualCommandHistory;
   
    private AbstractController controller;
   
    private int sentRows = 0;
    private long jobEstimate = 0L;
    private boolean G91Mode = false;

    // Other windows
    VisualizerWindow vw = null;
   
    // Duration timer
    private Timer timer;

    public enum ControlState {
        COMM_DISCONNECTED,
        COMM_IDLE,
        COMM_SENDING,
        COMM_SENDING_PAUSED,
        FILE_SELECTED,
    };
       
    // Static utilities
    private static NumberFormat formatter = new DecimalFormat("#.###", Localization.dfs);

    // Generated variables.
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu PendantMenu;
    private javax.swing.JLabel activeStateLabel;
    private javax.swing.JLabel activeStateValueLabel;
    private javax.swing.JCheckBox arrowMovementEnabled;
    private javax.swing.JLabel baudLabel;
    private javax.swing.JComboBox baudrateSelectionComboBox;
    private javax.swing.JTabbedPane bottomTabbedPane;
    private javax.swing.JButton browseButton;
    private javax.swing.JButton cancelButton;
    private javax.swing.JComboBox commPortComboBox;
    private javax.swing.JLabel commandLabel;
    private com.willwinder.universalgcodesender.uielements.GcodeTable commandTable;
    private javax.swing.JTextField commandTextField;
    private javax.swing.JPanel commandsPanel;
    private javax.swing.JPanel connectionPanel;
    private javax.swing.JTextArea consoleTextArea;
    private javax.swing.JTabbedPane controlContextTabbedPane;
    private javax.swing.JButton customGcodeButton1;
    private javax.swing.JButton customGcodeButton2;
    private javax.swing.JButton customGcodeButton3;
    private javax.swing.JButton customGcodeButton4;
    private javax.swing.JButton customGcodeButton5;
    private javax.swing.JTextField customGcodeText1;
    private javax.swing.JTextField customGcodeText2;
    private javax.swing.JTextField customGcodeText3;
    private javax.swing.JTextField customGcodeText4;
    private javax.swing.JTextField customGcodeText5;
    private javax.swing.JLabel durationLabel;
    private javax.swing.JLabel durationValueLabel;
    private javax.swing.JLabel fileLabel;
    private javax.swing.JPanel fileModePanel;
    private javax.swing.JPanel fileRunPanel;
    private javax.swing.JTextField fileTextField;
    private javax.swing.JComboBox firmwareComboBox;
    private javax.swing.JLabel firmwareLabel;
    private javax.swing.JMenu firmwareSettingsMenu;
    private javax.swing.JMenuItem grblConnectionSettingsMenuItem;
    private javax.swing.JMenuItem grblFirmwareSettingsMenuItem;
    private javax.swing.JButton helpButtonMachineControl;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem3;
    private javax.swing.JMenuItem jMenuItem4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JPanel keyboardMovementPanel;
    private javax.swing.JButton killAlarmLock;
    private javax.swing.JLabel latestCommentLabel;
    private javax.swing.JLabel latestCommentValueLabel;
    private javax.swing.ButtonGroup lineBreakGroup;
    private javax.swing.JPanel machineControlPanel;
    private javax.swing.JLabel machinePosition;
    private javax.swing.JLabel machinePositionXLabel;
    private javax.swing.JLabel machinePositionXValueLabel;
    private javax.swing.JLabel machinePositionYLabel;
    private javax.swing.JLabel machinePositionYValueLabel;
    private javax.swing.JLabel machinePositionZLabel;
    private javax.swing.JLabel machinePositionZValueLabel;
    private javax.swing.JLabel macroInstructions;
    private javax.swing.JPanel macroPanel;
    private javax.swing.JMenuBar mainMenuBar;
    private javax.swing.JPanel movementButtonPanel;
    private javax.swing.JButton opencloseButton;
    private javax.swing.JButton pauseButton;
    private javax.swing.JButton performHomingCycleButton;
    private javax.swing.JLabel portLabel;
    private javax.swing.JButton refreshButton;
    private javax.swing.JLabel remainingRowsLabel;
    private javax.swing.JLabel remainingRowsValueLabel;
    private javax.swing.JLabel remainingTimeLabel;
    private javax.swing.JLabel remainingTimeValueLabel;
    private javax.swing.JButton requestStateInformation;
    private javax.swing.JButton resetCoordinatesButton;
    private javax.swing.JButton resetXButton;
    private javax.swing.JButton resetYButton;
    private javax.swing.JButton resetZButton;
    private javax.swing.JButton returnToZeroButton;
    private javax.swing.JLabel rowsLabel;
    private javax.swing.JLabel rowsValueLabel;
    private javax.swing.JButton saveButton;
    private javax.swing.JCheckBox scrollWindowCheckBox;
    private javax.swing.JButton sendButton;
    private javax.swing.JLabel sentRowsLabel;
    private javax.swing.JLabel sentRowsValueLabel;
    private javax.swing.JMenu settingsMenu;
    private javax.swing.JCheckBox showVerboseOutputCheckBox;
    private javax.swing.JButton softResetMachineControl;
    private javax.swing.JMenuItem startPendantServerButton;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JLabel stepSizeLabel;
    private javax.swing.JSpinner stepSizeSpinner;
    private javax.swing.JMenuItem stopPendantServerButton;
    private javax.swing.JButton toggleCheckMode;
    private javax.swing.JButton visualizeButton;
    private javax.swing.JLabel workPositionLabel;
    private javax.swing.JLabel workPositionXLabel;
    private javax.swing.JLabel workPositionXValueLabel;
    private javax.swing.JLabel workPositionYLabel;
    private javax.swing.JLabel workPositionYValueLabel;
    private javax.swing.JLabel workPositionZLabel;
    private javax.swing.JLabel workPositionZValueLabel;
    private javax.swing.JButton xMinusButton;
    private javax.swing.JButton xPlusButton;
    private javax.swing.JButton yMinusButton;
    private javax.swing.JButton yPlusButton;
    private javax.swing.JButton zMinusButton;
    private javax.swing.JButton zPlusButton;
    // End of variables declaration//GEN-END:variables
}
TOP

Related Classes of com.willwinder.universalgcodesender.MainWindow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.