com.nwn.NwnUpdaterHomeView.java Source code

Java tutorial

Introduction

Here is the source code for com.nwn.NwnUpdaterHomeView.java

Source

/*
This file is part of NWN Server Updater.
    
NWN Server Updater 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.
    
NWN Server Updater 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 NWN Server Updater.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.nwn;

import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.text.DefaultCaret;
import org.apache.commons.validator.routines.UrlValidator;

/**
 *
 * @author Sam
 */
public class NwnUpdaterHomeView extends javax.swing.JFrame {
    private nwnUpdaterConfig config = nwnUpdaterConfig.getInstance();
    private Thread updaterThread;

    /**
     * Creates new form NwnUpdaterHomeView
     */
    public NwnUpdaterHomeView() {
        initComponents();
        updateUIComponents();
    }

    /**
     * Initialize gui components with data from config
     */
    private void updateUIComponents() {
        if (config.getNwnDir() != null) {
            txtNwnDir.setText(config.getNwnDir().toString());
        }
        for (ServerInfo serverInfo : config.getServerList()) {
            cmbServerList.addItem(serverInfo);
        }
    }

    /**
     * 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() {

        btnStartUpdate = new javax.swing.JButton();
        btnClose = new javax.swing.JButton();
        cmbServerList = new javax.swing.JComboBox();
        progressBarOverall = new javax.swing.JProgressBar();
        jScrollPane2 = new javax.swing.JScrollPane();
        txtOutput = new javax.swing.JTextArea();
        DefaultCaret caret = (DefaultCaret) txtOutput.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
        jLabel1 = new javax.swing.JLabel();
        btnRemoveServer = new javax.swing.JButton();
        btnAddServer = new javax.swing.JButton();
        txtNwnDir = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        btnSelectNwnDir = new javax.swing.JButton();
        progressBarTask = new javax.swing.JProgressBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("NWN Server Updater");

        btnStartUpdate.setText("Update");
        btnStartUpdate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStartUpdateActionPerformed(evt);
            }
        });

        btnClose.setText("Close");
        btnClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCloseActionPerformed(evt);
            }
        });

        txtOutput.setEditable(false);
        txtOutput.setBackground(new java.awt.Color(0, 0, 0));
        txtOutput.setColumns(20);
        txtOutput.setFont(new java.awt.Font("Arial", 0, 12)); // NOI18N
        txtOutput.setForeground(new java.awt.Color(0, 255, 0));
        txtOutput.setLineWrap(true);
        txtOutput.setRows(5);
        txtOutput.setText(
                "NWN Server Updater \nversion: 4.00\nBy: Skipper Warlock\nMay the work of DM Ronin stay undead forever.");
        txtOutput.setWrapStyleWord(true);
        txtOutput.setCaretColor(new java.awt.Color(0, 255, 0));
        txtOutput.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jScrollPane2.setViewportView(txtOutput);

        jLabel1.setText("Server:");

        btnRemoveServer.setText("Remove");
        btnRemoveServer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRemoveServerActionPerformed(evt);
            }
        });

        btnAddServer.setText("Add");
        btnAddServer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddServerActionPerformed(evt);
            }
        });

        txtNwnDir.setText("C:\\NeverwinterNights\\NWN");

        jLabel2.setText("NWN Dir:");

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

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(jScrollPane2)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(jLabel1).addComponent(jLabel2))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(layout.createSequentialGroup().addComponent(txtNwnDir)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(btnSelectNwnDir))
                                        .addComponent(cmbServerList, 0, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                Short.MAX_VALUE)))
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
                                layout.createSequentialGroup().addComponent(btnAddServer)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(btnRemoveServer))
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                        .addComponent(progressBarTask, javax.swing.GroupLayout.Alignment.LEADING,
                                                javax.swing.GroupLayout.PREFERRED_SIZE, 401,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addComponent(progressBarOverall, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                401, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btnStartUpdate)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(btnClose)))
                        .addContainerGap()));

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
                new java.awt.Component[] { btnClose, btnStartUpdate });

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
                new java.awt.Component[] { btnAddServer, btnRemoveServer });

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL,
                new java.awt.Component[] { progressBarOverall, progressBarTask });

        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(cmbServerList, javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel1))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(btnRemoveServer).addComponent(btnAddServer))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(txtNwnDir, javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel2).addComponent(btnSelectNwnDir))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 374,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addGroup(layout.createSequentialGroup()
                                        .addComponent(progressBarTask, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(progressBarOverall, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addComponent(btnStartUpdate, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(btnClose, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));

        layout.linkSize(javax.swing.SwingConstants.VERTICAL,
                new java.awt.Component[] { progressBarOverall, progressBarTask });

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Make sure updater gracefully closes then shutdown app
     * @param evt 
     */
    private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed
        btnClose.setEnabled(false);
        config.setNwnDir(txtNwnDir.getText());
        config.save();
        if (updaterThread == null) {
            System.exit(0);
        } else if (updaterThread.isAlive()) {
            updaterThread.interrupt();
            try {
                updaterThread.join();//wait for thread to close
            } catch (InterruptedException ex) {
                appendOutputText("\nERROR: Cannot close updater. Please try again later.");
                btnClose.setEnabled(true);
            }
            System.exit(0);
        } else {
            System.exit(0);
        }
    }//GEN-LAST:event_btnCloseActionPerformed

    /**
     * Allow user to specify their NWN directory
     * @param evt 
     */
    private void btnSelectNwnDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSelectNwnDirActionPerformed
        JFileChooser fc = new JFileChooser();
        fc.setCurrentDirectory(new java.io.File("."));
        fc.setDialogTitle("NWN Updater");
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fc.setAcceptAllFileFilterUsed(false);
        int returnVal = fc.showOpenDialog(txtNwnDir);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            txtNwnDir.setText(file.getAbsolutePath());
        }
    }//GEN-LAST:event_btnSelectNwnDirActionPerformed

    /**
     * Add server and save it to config
     * Ensure the server name and url are valid and follow the same pattern 
     * that we expect to read from the config
     * @param evt 
     */
    private void btnAddServerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddServerActionPerformed
        //Regex validation is here to make sure we can read the config later. 
        //this should be changed both here and on the config object
        //todo: enum for regex values
        String newServerName, newServerFileUrl = null;
        String[] schemes = { "http", "https" };
        UrlValidator urlValidator = new UrlValidator(schemes);
        String nameMessage = "Server Name:\n";
        String urlMessage = "Server File URL:\n";
        do {
            newServerName = (String) JOptionPane.showInputDialog(null, nameMessage, "Add Server",
                    JOptionPane.PLAIN_MESSAGE);
            if (newServerName == null) {
                break;
            }
            if (newServerName.contains(",")) {
                nameMessage = "Name cannot have commas:\n";
                newServerName = "";
            }
        } while ((newServerName.length() == 0));
        do {
            if (newServerName == null) {
                break;
            }
            newServerFileUrl = (String) JOptionPane.showInputDialog(null, urlMessage, "Add Server",
                    JOptionPane.PLAIN_MESSAGE);
            if (newServerFileUrl == null) {
                break;
            }
            if (!urlValidator.isValid(newServerFileUrl)) {
                urlMessage = "Please Enter Valid Url:\n";
                newServerFileUrl = "";
            }
        } while ((newServerFileUrl.length() == 0));
        if (newServerName != null && newServerFileUrl != null) {
            try {
                ServerInfo newServer = new ServerInfo(newServerName, new URL(newServerFileUrl));
                config.getServerList().add(newServer);
                cmbServerList.addItem(newServer);
                nwnUpdaterConfig.getInstance().save();
            } catch (Exception ex) {
                //            ex.printStackTrace();
                appendOutputText("\nERROR: Unknown error occured, cannot add server: " + newServerName);
            }
        }
    }//GEN-LAST:event_btnAddServerActionPerformed

    /**
     * Delete server from gui and config
     * Currently this cannot be undone
     * @param evt 
     */
    private void btnRemoveServerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveServerActionPerformed
        ServerInfo selectedServer = (ServerInfo) cmbServerList.getSelectedItem();
        int confirm = JOptionPane.showConfirmDialog(null,
                "Are you sure you want to delete " + selectedServer.getServerName() + "?", "Warning",
                JOptionPane.YES_NO_OPTION);
        if (confirm == JOptionPane.YES_OPTION) {
            config.getServerList().remove(cmbServerList.getSelectedItem());
            cmbServerList.removeItemAt(cmbServerList.getSelectedIndex());
            config.save();
        }
    }//GEN-LAST:event_btnRemoveServerActionPerformed

    /**
     * Start our update process
     * While the process is running, our update button will act as the stop/cancel button
     * @param evt 
     */
    private void btnStartUpdateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartUpdateActionPerformed
        if (updaterThread == null) {
            startUpdateThread();
        } else if (updaterThread.isAlive()) {
            updaterThread.interrupt();
            btnStartUpdate.setEnabled(false);
            try {
                updaterThread.join();//wait for thread to close
            } catch (InterruptedException ex) {
                //            ex.printStackTrace();
                appendOutputText("\nERROR: Cannot close updater. Please restart the application.");
            }
            btnStartUpdate.setEnabled(true);
        } else {
            startUpdateThread();
        }
    }//GEN-LAST:event_btnStartUpdateActionPerformed

    /**
     * Set text value for update button
     * @param newText new update button text
     */
    public void setUpdateBtnText(String newText) {
        btnStartUpdate.setText(newText);
    }

    /**
     * Set value for Overall Progress Bar
     * @param newValue new Overall Progress Bar value
     */
    public void setOverallProgressBarValue(int newValue) {
        progressBarOverall.setValue(newValue);
    }

    /**
     * Set value for Task Progress Bar
     * @param newValue new Task Progress Bar value
     */
    public void setTaskProgressBarValue(int newValue) {
        progressBarTask.setValue(newValue);
    }

    /**
     * Add text to Output Box
     * @param newText new text to append
     */
    public void appendOutputText(String newText) {
        txtOutput.append(newText);
    }

    /**
     * Perform actions necessary to start the update process
     */
    private void startUpdateThread() {
        if (!NwnFileHandler.isValidNwnDirectory(txtNwnDir.getText(), "nwmain.exe")) {
            appendOutputText("\nPlease provide a valid NWN Directory");
        } else if (cmbServerList.getItemCount() <= 0) {
            appendOutputText("\nNo Server Specified");
        } else {
            progressBarTask.setValue(0);
            progressBarOverall.setValue(0);
            btnStartUpdate.setEnabled(false);
            ServerInfo selectedServer = (ServerInfo) cmbServerList.getSelectedItem();
            config.setNwnDir(txtNwnDir.getText());
            config.save();
            File serverFileDir = new File(config.getNwnDir().toString() + File.separator + "UpdaterServerFiles");
            if (!serverFileDir.exists()) {
                serverFileDir.mkdir();
            }
            NwnFileHandler.downloadFile(selectedServer.getFileUrl().toString(),
                    serverFileDir.toString() + File.separator + selectedServer.getServerName() + ".json");
            Path serverJson = Paths
                    .get(serverFileDir.toString() + File.separator + selectedServer.getServerName() + ".json");
            NwnUpdater nwnUpdater = new NwnUpdater(config.getNwnDir(), serverJson, this);
            updaterThread = new Thread(nwnUpdater, "Update Thread");
            updaterThread.start();
            btnStartUpdate.setEnabled(true);
        }
    }

    //   /**
    //    * @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(NwnUpdaterHomeView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    //      } catch (InstantiationException ex) {
    //         java.util.logging.Logger.getLogger(NwnUpdaterHomeView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    //      } catch (IllegalAccessException ex) {
    //         java.util.logging.Logger.getLogger(NwnUpdaterHomeView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    //      } catch (javax.swing.UnsupportedLookAndFeelException ex) {
    //         java.util.logging.Logger.getLogger(NwnUpdaterHomeView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    //      }
    //        //</editor-fold>
    //
    //      /* Create and display the form */
    //      java.awt.EventQueue.invokeLater(new Runnable() {
    //         public void run() {
    //            nwnUpdaterConfig.getInstance().load("NwnUpdater.cfg");
    //            new NwnUpdaterHomeView().setVisible(true);
    //         }
    //      });
    //   }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddServer;
    private javax.swing.JButton btnClose;
    private javax.swing.JButton btnRemoveServer;
    private javax.swing.JButton btnSelectNwnDir;
    private javax.swing.JButton btnStartUpdate;
    private javax.swing.JComboBox cmbServerList;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JProgressBar progressBarOverall;
    private javax.swing.JProgressBar progressBarTask;
    private javax.swing.JTextField txtNwnDir;
    private javax.swing.JTextArea txtOutput;
    // End of variables declaration//GEN-END:variables
}