Java tutorial
/* 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 }