Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 672   Methods: 32
NCLOC: 512   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
NewVersionPopup.java 0% 0% 0% 0%
coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.ui;
 38   
 39    import javax.swing.*;
 40    import javax.swing.border.*;
 41    import java.awt.event.*;
 42    import java.awt.*;
 43    import java.io.*;
 44    import java.net.*;
 45    import java.text.SimpleDateFormat;
 46    import java.util.*;
 47    import java.util.jar.*;
 48   
 49    import edu.rice.cs.drjava.*;
 50    import edu.rice.cs.drjava.config.OptionConstants;
 51    import edu.rice.cs.drjava.platform.*;
 52    import edu.rice.cs.util.swing.Utilities;
 53    import edu.rice.cs.plt.lambda.Runnable1;
 54    import edu.rice.cs.plt.lambda.LambdaUtil;
 55    import edu.rice.cs.plt.lambda.Box;
 56    import edu.rice.cs.plt.lambda.SimpleBox;
 57    import edu.rice.cs.plt.concurrent.JVMBuilder;
 58    import edu.rice.cs.util.FileOps;
 59   
 60    /** Displays whether a new version of DrJava is available.
 61    * @version $Id: NewVersionPopup.java 5252 2010-05-10 23:26:18Z mgricken $
 62    */
 63    public class NewVersionPopup extends JDialog {
 64    /** whether to keep displaying this dialog, and for which releases */
 65    private JComboBox _modeBox;
 66    /** the button that closes this window */
 67    private JButton _closeButton;
 68    /** the button that updates to the new version */
 69    private JButton _updateButton;
 70    /** the button that downloads the new version */
 71    private JButton _downloadButton;
 72    /** the parent frame */
 73    private MainFrame _mainFrame;
 74    /** the version information pane */
 75    private JOptionPane _versionPanel;
 76    /** the panel with the buttons and combobox */
 77    private JPanel _bottomPanel;
 78    /** the build time of this version */
 79    private static Date BUILD_TIME = Version.getBuildTime();
 80    /** the message for the user */
 81    private String[] _msg = null;
 82    /** the version string of the new version found, or "" */
 83    private String _newestVersionString = "";
 84    /** indeterminate progress bar */
 85   
 86    /** Creates a window to display whether a new version of DrJava is available. */
 87  0 public NewVersionPopup(MainFrame parent) {
 88  0 super(parent, "Check for New Version of DrJava");
 89  0 setResizable(false);
 90   
 91  0 _mainFrame = parent;
 92  0 _mainFrame.setPopupLoc(this);
 93  0 this.setSize(500,150);
 94   
 95  0 _modeBox = new JComboBox(OptionConstants.NEW_VERSION_NOTIFICATION_CHOICES.toArray());
 96  0 for(int i = 0; i < OptionConstants.NEW_VERSION_NOTIFICATION_CHOICES.size(); ++i) {
 97  0 if (DrJava.getConfig().getSetting(OptionConstants.NEW_VERSION_NOTIFICATION)
 98    .equals(OptionConstants.NEW_VERSION_NOTIFICATION_CHOICES.get(i))) {
 99  0 _modeBox.setSelectedIndex(i);
 100  0 break;
 101    }
 102    }
 103  0 _modeBox.addActionListener(new ActionListener() {
 104  0 public void actionPerformed(ActionEvent e) {
 105  0 DrJava.getConfig().setSetting(OptionConstants.NEW_VERSION_NOTIFICATION,
 106    OptionConstants.NEW_VERSION_NOTIFICATION_CHOICES.get(_modeBox.getSelectedIndex()));
 107  0 _msg = null;
 108  0 updateText();
 109    }
 110    });
 111   
 112  0 _updateButton = new JButton(_updateAction);
 113  0 _downloadButton = new JButton(_downloadAction);
 114  0 _closeButton = new JButton(_closeAction);
 115  0 _updateButton.setEnabled(false);
 116  0 _downloadButton.setEnabled(false);
 117   
 118  0 _bottomPanel = new JPanel(new BorderLayout());
 119  0 JPanel buttonPanel = new JPanel();
 120  0 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
 121  0 buttonPanel.add(_updateButton);
 122  0 buttonPanel.add(_downloadButton);
 123  0 buttonPanel.add(_closeButton);
 124  0 _bottomPanel.add(buttonPanel, BorderLayout.CENTER);
 125  0 JPanel comboPanel = new JPanel();
 126  0 comboPanel.add(new JLabel("Check for: "));
 127  0 comboPanel.add(_modeBox);
 128  0 _bottomPanel.add(comboPanel, BorderLayout.WEST);
 129   
 130  0 updateText();
 131    }
 132   
 133  0 private void updateText() {
 134  0 if (_msg != null) {
 135  0 _versionPanel = new JOptionPane(_msg,JOptionPane.INFORMATION_MESSAGE,
 136    JOptionPane.DEFAULT_OPTION,null,
 137    new Object[0]);
 138   
 139  0 JPanel cp = new JPanel(new BorderLayout(5,5));
 140  0 cp.setBorder(new EmptyBorder(5,5,5,5));
 141  0 setContentPane(cp);
 142  0 cp.add(_versionPanel, BorderLayout.CENTER);
 143  0 cp.add(_bottomPanel, BorderLayout.SOUTH);
 144  0 getRootPane().setDefaultButton(_closeButton);
 145  0 setTitle("Check for New Version of DrJava");
 146  0 pack();
 147  0 _mainFrame.setPopupLoc(this);
 148  0 return;
 149    }
 150  0 setTitle("Checking for new versions, please wait...");
 151  0 String[] msg = new String[] {"Checking drjava.org for new versions.", "Please wait..."};
 152  0 _versionPanel = new JOptionPane(msg,JOptionPane.INFORMATION_MESSAGE,
 153    JOptionPane.DEFAULT_OPTION,null,
 154    new Object[0]);
 155  0 JPanel cp = new JPanel(new BorderLayout(5,5));
 156  0 cp.setBorder(new EmptyBorder(5,5,5,5));
 157  0 setContentPane(cp);
 158  0 cp.add(_versionPanel, BorderLayout.CENTER);
 159  0 cp.add(_bottomPanel, BorderLayout.SOUTH);
 160  0 getRootPane().setDefaultButton(_closeButton);
 161  0 pack();
 162  0 _mainFrame.setPopupLoc(this);
 163    // clearEventQueue must not be called from the event thread
 164    //Utilities.clearEventQueue(false); // Why? In principle, its inclusion does not change the semantics of the program
 165   
 166  0 EventQueue.invokeLater(new Runnable() {
 167  0 public void run() {
 168  0 _msg = getMessage(null);
 169  0 _versionPanel = new JOptionPane(_msg,JOptionPane.INFORMATION_MESSAGE,
 170    JOptionPane.DEFAULT_OPTION,null,
 171    new Object[0]);
 172   
 173  0 JPanel cp = new JPanel(new BorderLayout(5,5));
 174  0 cp.setBorder(new EmptyBorder(5,5,5,5));
 175  0 setContentPane(cp);
 176  0 cp.add(_versionPanel, BorderLayout.CENTER);
 177  0 cp.add(_bottomPanel, BorderLayout.SOUTH);
 178  0 getRootPane().setDefaultButton(_closeButton);
 179  0 setTitle("Check for New Version of DrJava");
 180  0 pack();
 181  0 _mainFrame.setPopupLoc(NewVersionPopup.this);
 182    }
 183    });
 184    }
 185   
 186    /* Close the window. */
 187    private Action _closeAction = new AbstractAction("Close") {
 188  0 public void actionPerformed(ActionEvent e) { closeAction(); }
 189    };
 190   
 191    /** Download new DrJava and update this DrJava, then restart. */
 192    private Action _updateAction = new AbstractAction("Automatic Update") {
 193  0 public void actionPerformed(ActionEvent e) { updateAction(); }
 194    };
 195   
 196    /** Close this window, but display the full DrJava Errors window. */
 197    private Action _downloadAction = new AbstractAction("Manual Download") {
 198  0 public void actionPerformed(ActionEvent e) { downloadAction(); }
 199    };
 200   
 201  0 protected void closeAction() {
 202  0 NewVersionPopup.this.setVisible(false);
 203  0 NewVersionPopup.this.dispose();
 204    }
 205   
 206  0 protected void downloadAction() {
 207  0 closeAction();
 208  0 _openFileDownloadPage(getManualDownloadURL());
 209    }
 210   
 211    public static final edu.rice.cs.util.Log LOG = new edu.rice.cs.util.Log("version.txt",false);
 212   
 213  0 protected void abortUpdate() {
 214  0 abortUpdate("", false);
 215    }
 216   
 217  0 protected void abortUpdate(String message) {
 218  0 abortUpdate(message, false);
 219    }
 220   
 221  0 protected void abortUpdate(boolean close) {
 222  0 abortUpdate("", close);
 223    }
 224   
 225  0 protected void abortUpdate(String message, boolean close) {
 226  0 LOG.log(message);
 227  0 if (close) closeAction();
 228  0 StringBuilder sb = new StringBuilder();
 229  0 sb.append("Could not update DrJava automatically");
 230  0 if (message.length() > 0) {
 231  0 sb.append(":\n");
 232  0 sb.append(message);
 233    }
 234    else {
 235  0 sb.append('.');
 236    }
 237  0 sb.append("\nPlease download DrJava yourself.");
 238  0 JOptionPane.showMessageDialog(this, sb.toString(),
 239    "Error Updating DrJava", JOptionPane.ERROR_MESSAGE);
 240  0 downloadAction();
 241    }
 242   
 243  0 protected void updateAction() {
 244  0 JPanel cp = new JPanel(new BorderLayout(5,5));
 245  0 cp.setBorder(new EmptyBorder(5,5,5,5));
 246  0 setContentPane(cp);
 247  0 cp.add(new JOptionPane("Waiting for www.sourceforge.net ...",JOptionPane.INFORMATION_MESSAGE,
 248    JOptionPane.DEFAULT_OPTION,null,
 249    new Object[0]), BorderLayout.CENTER);
 250  0 JProgressBar pb = new JProgressBar(0,100);
 251  0 pb.setIndeterminate(true);
 252  0 cp.add(pb, BorderLayout.SOUTH);
 253  0 validate();
 254   
 255  0 new Thread(new Runnable() {
 256  0 public void run() {
 257    // list of things to clean up in case the update fails or is aborted
 258  0 ArrayList<File> toCleanUp = new ArrayList<File>();
 259   
 260  0 try {
 261  0 LOG.log("updateAction");
 262   
 263  0 final File targetFile = FileOps.getDrJavaApplicationFile();
 264  0 LOG.log("\ttargetFile = "+targetFile);
 265  0 if ((targetFile == null) || (targetFile.getParentFile() == null)) {
 266  0 abortUpdate("Could not determine where DrJava is located on this computer.", true);
 267  0 return;
 268    }
 269   
 270    // determine file name
 271  0 String fileName = _newestVersionString;
 272  0 final int lastDotPos = fileName.length();
 273  0 if (targetFile.toString().endsWith(".jar")) { fileName += ".jar"; }
 274  0 else if (targetFile.toString().endsWith(".exe")) { fileName += ".exe"; }
 275  0 else if (targetFile.toString().endsWith(".app")) { fileName += "-osx.tar.gz"; }
 276  0 else { abortUpdate("Could not determine the file type to download.", true); return; }
 277  0 LOG.log("\tfileName = "+fileName);
 278   
 279    // determine temp file name
 280  0 File destFile = FileOps.generateNewFileName(targetFile.getParentFile(),
 281    fileName.substring(0,lastDotPos),
 282    fileName.substring(lastDotPos));
 283  0 toCleanUp.add(destFile);
 284  0 LOG.log("Downloading to "+destFile);
 285   
 286  0 File macTempDir = null;
 287  0 File macTarFile = null;
 288  0 if (fileName.endsWith("-osx.tar.gz")) {
 289    // assume this is on the Mac
 290    // check that tar exists
 291  0 macTarFile = new File("/usr/bin/tar");
 292  0 LOG.log("Searching for "+macTarFile);
 293  0 if (!macTarFile.exists()) {
 294  0 String path = System.getenv("PATH");
 295  0 for(String p: path.split(System.getProperty("path.separator"))) {
 296  0 macTarFile = new File(p, "tar");
 297  0 LOG.log("Searching for "+macTarFile);
 298  0 if (macTarFile.exists()) break;
 299    }
 300  0 if (!macTarFile.exists()) { abortUpdate("Could not find tar on this computer.", true); return; }
 301    }
 302   
 303    // determine temporary directory
 304  0 macTempDir = FileOps.generateNewFileName(destFile.getParentFile(), _newestVersionString);
 305    }
 306   
 307    // extract DrJavaRestart from this jar
 308  0 final File tempClassFile = File.createTempFile("drjavarestart-",".jar");
 309  0 toCleanUp.add(tempClassFile);
 310  0 BufferedOutputStream tempClassOut = new BufferedOutputStream(new FileOutputStream(tempClassFile));
 311  0 BufferedInputStream tempClassIn = new BufferedInputStream(new FileInputStream(FileOps.getDrJavaFile()));
 312  0 edu.rice.cs.plt.io.IOUtil.copyInputStream(tempClassIn, tempClassOut);
 313  0 tempClassIn.close();
 314  0 tempClassOut.close();
 315  0 LOG.log("Copied drjava.jar to "+tempClassFile);
 316   
 317    // download new file
 318  0 URL fileURL = new URL(getAutomaticDownloadURL()+fileName);
 319  0 LOG.log("fileURL = "+fileURL);
 320   
 321  0 URLConnection uc = fileURL.openConnection();
 322  0 final int length = uc.getContentLength();
 323  0 InputStream in = uc.getInputStream();
 324  0 ProgressMonitorInputStream pin = new ProgressMonitorInputStream(_mainFrame, "Downloading "+fileName+" ...", in);
 325  0 ProgressMonitor pm = pin.getProgressMonitor();
 326  0 pm.setMaximum(length);
 327  0 pm.setMillisToDecideToPopup(0);
 328  0 pm.setMillisToPopup(0);
 329  0 EventQueue.invokeLater(new Runnable() { public void run() { closeAction(); } });
 330   
 331  0 BufferedInputStream bin = new BufferedInputStream(pin);
 332  0 BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(destFile));
 333  0 edu.rice.cs.plt.io.IOUtil.copyInputStream(bin,bout);
 334  0 bin.close();
 335  0 bout.close();
 336  0 if ((!destFile.exists()) || (destFile.length() != length)) {
 337  0 abortUpdate("Could not download update."); return;
 338    }
 339   
 340  0 LOG.log("Downloaded to "+destFile);
 341   
 342  0 if (fileName.endsWith("-osx.tar.gz")) {
 343    // assume this is on the Mac, make temporary directory and tar xfz
 344  0 macTempDir.mkdirs();
 345  0 toCleanUp.add(macTempDir);
 346  0 Process p = new ProcessBuilder()
 347    .command(macTarFile.getAbsolutePath(), "xfz", destFile.getAbsolutePath())
 348    .directory(macTempDir)
 349    .redirectErrorStream(true)
 350    .start();
 351  0 boolean waiting = false;
 352  0 do {
 353  0 try {
 354  0 p.waitFor();
 355  0 waiting = false;
 356    }
 357  0 catch(InterruptedException ie) { abortUpdate("Installation was interrupted."); return; }
 358  0 } while(waiting);
 359  0 if (p.exitValue() != 0) { abortUpdate("Unpacking with tar failed."); return; }
 360    // delete tar.gz file
 361  0 destFile.delete();
 362  0 destFile = new File(macTempDir, "DrJava.app");
 363  0 if (!destFile.exists() ||
 364    !new File(destFile,"Contents/Resources/Java/drjava.jar").exists()) {
 365  0 abortUpdate("Downloaded file contained unexpected files."); return;
 366    }
 367    }
 368    else {
 369    // this is a jar or exe file, check that it can be opened as a JarFile
 370  0 JarFile jf = new JarFile(destFile);
 371    }
 372   
 373    // we got to this point, assume that we have successfully downloaded everything
 374    // clear the list of files to clean up
 375  0 toCleanUp.clear();
 376   
 377    // ask DrJava to close
 378  0 final File finalDestFile = destFile;
 379  0 Thread restart = new Thread() {
 380  0 public void run() {
 381  0 try {
 382  0 LOG.log("Restarting...");
 383  0 Process p = JVMBuilder.DEFAULT.classPath(tempClassFile).start(DrJavaRestart.class.getName(),
 384    finalDestFile.getAbsolutePath(),
 385    targetFile.getAbsolutePath(),
 386    tempClassFile.getAbsolutePath());
 387    }
 388    catch(Exception e) {
 389  0 LOG.log("Exception in shutdown hook: "+e);
 390  0 tempClassFile.delete();
 391  0 JOptionPane.showMessageDialog(null,
 392    "A new version of DrJava was downloaded. However,\n"+
 393    "it could not be started automatically.\n\n"+
 394    "The new copy is now installed at:\n"+
 395    finalDestFile.getAbsolutePath()+"\n\n"+
 396    "The old copy is still installed at:\n"+
 397    targetFile.getAbsolutePath()+"\n\n"+
 398    "Please start DrJava manually.",
 399    "Error Updating DrJava", JOptionPane.ERROR_MESSAGE);
 400    // NOTE: it would be nice if this error message would keep the application alive until the user closes it
 401    }
 402    }
 403    };
 404  0 Runtime.getRuntime().addShutdownHook(restart);
 405  0 Utilities.invokeAndWait(new Runnable() { public void run() { _mainFrame.quit(); } });
 406    // if we get here, then the user has cancelled the shutdown
 407    // remove the hook
 408  0 Runtime.getRuntime().removeShutdownHook(restart);
 409  0 tempClassFile.delete();
 410  0 JOptionPane.showMessageDialog(_mainFrame,
 411    "A new version of DrJava was downloaded. However, you chose\n"+
 412    "not to restart DrJava, so the old version was not automatically\n"+
 413    "replaced.\n\n"+
 414    "The new copy is now installed at:\n"+
 415    finalDestFile.getAbsolutePath()+"\n\n"+
 416    "The old copy is still installed at:\n"+
 417    targetFile.getAbsolutePath());
 418    }
 419  0 catch(InterruptedIOException iie) { /* aborted by user */ return; }
 420    catch(final IOException e) {
 421  0 EventQueue.invokeLater(new Runnable() {
 422  0 public void run() {
 423  0 abortUpdate("Error installing update:\n"+e.getMessage()); return;
 424    }
 425    });
 426    }
 427    finally {
 428    // clean up files
 429  0 for(File f: toCleanUp) { edu.rice.cs.plt.io.IOUtil.deleteRecursively(f); }
 430    }
 431    }
 432    }).start();
 433    }
 434   
 435    /** Return the automatic download URL. */
 436  0 protected String getAutomaticDownloadURL() {
 437  0 if (_newestVersionString.indexOf("weekly") > 0) {
 438  0 return "http://www.cs.rice.edu/~javaplt/drjavarice/weekly/files/";
 439    }
 440    else {
 441  0 return "http://prdownloads.sourceforge.net/drjava/";
 442    }
 443    }
 444   
 445    /** Return the manual download URL. */
 446  0 protected String getManualDownloadURL() {
 447  0 if (_newestVersionString.indexOf("weekly") > 0) {
 448  0 return "http://www.cs.rice.edu/~javaplt/drjavarice/weekly/";
 449    }
 450  0 final String DRJAVA_FILES_PAGE = "http://sourceforge.net/project/showfiles.php?group_id=44253";
 451  0 final String LINK_PREFIX = "<a href=\"/project/showfiles.php?group_id=44253";
 452  0 final String LINK_SUFFIX = "\">";
 453  0 BufferedReader br = null;
 454  0 try {
 455  0 URL url = new URL(DRJAVA_FILES_PAGE);
 456  0 InputStream urls = url.openStream();
 457  0 InputStreamReader is = new InputStreamReader(urls);
 458  0 br = new BufferedReader(is);
 459  0 String line;
 460  0 int pos;
 461    // search for the link to the version
 462  0 while((line = br.readLine()) != null) {
 463  0 if ((pos = line.indexOf(_newestVersionString)) >= 0) {
 464  0 int prePos = line.indexOf(LINK_PREFIX);
 465  0 if ((prePos >= 0) && (prePos < pos)) {
 466  0 int suffixPos = line.indexOf(LINK_SUFFIX, prePos);
 467  0 if ((suffixPos >= 0) && (suffixPos + LINK_SUFFIX.length() == pos)) {
 468  0 String versionLink =
 469    edu.rice.cs.plt.text.TextUtil.xmlUnescape(line.substring(prePos + LINK_PREFIX.length(), suffixPos));
 470  0 return DRJAVA_FILES_PAGE + versionLink;
 471    }
 472    }
 473    }
 474    };
 475    }
 476  0 catch(IOException e) { return DRJAVA_FILES_PAGE; }
 477    finally { // close open input stream
 478  0 try { if (br != null) br.close(); }
 479    catch(IOException e) { /* ignore */ }
 480    }
 481  0 return DRJAVA_FILES_PAGE;
 482    }
 483   
 484    /** Opens the specified page. */
 485  0 private void _openFileDownloadPage(String url) {
 486  0 try { PlatformFactory.ONLY.openURL(new URL(url)); }
 487    catch(Exception ex) { /* ignore */ }
 488    }
 489   
 490    /** Returns true if there is a new version available that matches the users criterion. */
 491  0 public boolean checkNewVersion() {
 492  0 Box<Boolean> availableRef = new SimpleBox<Boolean>(false);
 493  0 getMessage(availableRef);
 494  0 return availableRef.value();
 495    }
 496   
 497  0 @SuppressWarnings("fallthrough")
 498    protected String[] getMessage(Box<Boolean> availableRef) {
 499  0 Box<String> stableString = new SimpleBox<String>("");
 500  0 Box<String> betaString = new SimpleBox<String>("");
 501  0 Box<String> devString = new SimpleBox<String>("");
 502  0 Box<String> weeklyString = new SimpleBox<String>("");
 503  0 Box<Date> stableTime = new SimpleBox<Date>(new Date(0));
 504  0 Box<Date> betaTime = new SimpleBox<Date>(new Date(0));
 505  0 Box<Date> devTime = new SimpleBox<Date>(new Date(0));
 506  0 Box<Date> weeklyTime = new SimpleBox<Date>(new Date(0));
 507  0 boolean newVersion = false;
 508  0 _newestVersionString = "";
 509  0 if (availableRef != null) { availableRef.set(false); }
 510  0 switch(_modeBox.getSelectedIndex()) {
 511  0 case 3: if (FileOps.getDrJavaApplicationFile().toString().endsWith(".jar")) { // only consider weekly builds if using *.jar file
 512  0 newVersion |= checkNewWeeklyVersion(weeklyString,weeklyTime); // fall-through required, not a mistake
 513    }
 514  0 case 2:
 515  0 newVersion |= checkNewDevVersion(devString,devTime); // fall-through required, not a mistake
 516  0 case 1:
 517  0 newVersion |= checkNewBetaVersion(betaString,betaTime); // fall-through required, not a mistake
 518  0 case 0:
 519  0 newVersion |= checkNewStableVersion(stableString,stableTime);
 520  0 _updateButton.setEnabled(newVersion);
 521  0 _downloadButton.setEnabled(newVersion);
 522  0 DrJava.getConfig().setSetting(OptionConstants.LAST_NEW_VERSION_NOTIFICATION, new Date().getTime());
 523  0 if (availableRef != null) { availableRef.set(newVersion); }
 524  0 if (newVersion) {
 525  0 TreeMap<Date,String[]> versionSorter = new TreeMap<Date,String[]>();
 526  0 versionSorter.put(stableTime.value(),new String[] {"stable release", stableString.value() });
 527  0 versionSorter.put(betaTime.value(), new String[] {"beta release", betaString.value() });
 528  0 versionSorter.put(devTime.value(), new String[] {"development release", devString.value() });
 529  0 versionSorter.put(weeklyTime.value(),new String[] {"weekly build", weeklyString.value() });
 530  0 String newestType = versionSorter.get(versionSorter.lastKey())[0];
 531  0 _newestVersionString = versionSorter.get(versionSorter.lastKey())[1];
 532   
 533  0 return new String[] {
 534    "A new "+newestType+" has been found.",
 535    "The new version is: "+_newestVersionString,
 536    "Do you want to download this new version?"};
 537    }
 538    else {
 539  0 if (availableRef != null) { availableRef.set(false); }
 540  0 return new String[] {
 541    "No new version of DrJava has been found.", "You are using the newest version that matches your criterion."};
 542    }
 543  0 default:
 544  0 _updateButton.setEnabled(false);
 545  0 _downloadButton.setEnabled(false);
 546  0 return new String[] { "Checking for new versions has been disabled.", "You can change this setting below." };
 547    }
 548    }
 549   
 550    /** Return true if there is a stable release available that's newer than this version.
 551    * @param versionStringRef a reference that will be filled with the version string, or null if not desired
 552    * @param buildTimeRef a reference that will be filled with the build time, or null if not desired
 553    * @return true if newer stable version is available */
 554  0 public static boolean checkNewStableVersion(Box<String> versionStringRef,
 555    Box<Date> buildTimeRef) {
 556  0 try {
 557  0 Date newestTime = getBuildTime(new URL("http://www.drjava.org/LATEST_VERSION.TXT"), versionStringRef);
 558  0 if (newestTime == null) { return false; }
 559  0 if (buildTimeRef != null) { buildTimeRef.set(newestTime); }
 560  0 return BUILD_TIME.before(newestTime);
 561    }
 562  0 catch(MalformedURLException e) { return false; }
 563    }
 564    /** Return true if there is a beta release available that's newer than this version.
 565    * @param versionStringRef a reference that will be filled with the version string, or null if not desired
 566    * @param buildTimeRef a reference that will be filled with the build time, or null if not desired
 567    * @return true if newer beta version is available */
 568  0 public static boolean checkNewBetaVersion(Box<String> versionStringRef,
 569    Box<Date> buildTimeRef) {
 570  0 try {
 571  0 Date newestTime = getBuildTime(new URL("http://www.drjava.org/LATEST_BETA_VERSION.TXT"), versionStringRef);
 572  0 if (newestTime == null) { return false; }
 573  0 if (buildTimeRef != null) { buildTimeRef.set(newestTime); }
 574  0 return BUILD_TIME.before(newestTime);
 575    }
 576  0 catch(MalformedURLException e) { return false; }
 577    }
 578    /** Return true if there is a development release available that's newer than this version.
 579    * @param versionStringRef a reference that will be filled with the version string, or null if not desired
 580    * @param buildTimeRef a reference that will be filled with the build time, or null if not desired
 581    * @return true if newer development version is available */
 582  0 public static boolean checkNewDevVersion(Box<String> versionStringRef,
 583    Box<Date> buildTimeRef) {
 584  0 try {
 585  0 Date newestTime = getBuildTime(new URL("http://www.drjava.org/LATEST_DEV_VERSION.TXT"), versionStringRef);
 586  0 if (newestTime == null) { return false; }
 587  0 if (buildTimeRef != null) { buildTimeRef.set(newestTime); }
 588  0 return BUILD_TIME.before(newestTime);
 589    }
 590  0 catch(MalformedURLException e) { return false; }
 591    }
 592   
 593    /** Return true if there is a weekly build available that's newer than this version.
 594    * @param versionStringRef a reference that will be filled with the version string, or null if not desired
 595    * @param buildTimeRef a reference that will be filled with the build time, or null if not desired
 596    * @return true if newer development version is available */
 597  0 public static boolean checkNewWeeklyVersion(Box<String> versionStringRef,
 598    Box<Date> buildTimeRef) {
 599  0 try {
 600  0 Date newestTime = getBuildTime(new URL("http://www.cs.rice.edu/~javaplt/drjavarice/weekly/LATEST_WEEKLY_VERSION.TXT"), versionStringRef);
 601  0 if (newestTime == null) { return false; }
 602  0 if (buildTimeRef != null) { buildTimeRef.set(newestTime); }
 603  0 return BUILD_TIME.before(newestTime);
 604    }
 605  0 catch(MalformedURLException e) { return false; }
 606    }
 607   
 608    /** Returns the build time for the URL, or null if it could not be read. */
 609  0 public static Date getBuildTime(URL url) {
 610  0 return getBuildTime(url, null);
 611    }
 612   
 613    /** Returns the build time for the URL, or null if it could not be read.
 614    * @param url the URL that contains the version string
 615    * @param versionStringRef a reference that will be filled with the version string, or null if not desired
 616    * @return build time, or null if there was an error */
 617  0 public static Date getBuildTime(URL url, Box<String> versionStringRef) {
 618  0 try {
 619  0 InputStream urls = url.openStream();
 620  0 InputStreamReader is = null;
 621  0 BufferedReader br = null;
 622  0 is = new InputStreamReader(urls);
 623  0 br = new BufferedReader(is);
 624  0 String line = br.readLine();
 625  0 if (versionStringRef != null) { versionStringRef.set(line); }
 626  0 br.close();
 627   
 628    // remove "drjava-" prefix
 629  0 final String DRJAVA_PREFIX = "drjava-";
 630  0 if (!line.startsWith(DRJAVA_PREFIX)) { return null; }
 631  0 line = line.substring(DRJAVA_PREFIX.length());
 632    // remove "stable-" prefix
 633  0 final String STABLE_PREFIX = "stable-";
 634  0 if (line.startsWith(STABLE_PREFIX)) { line = line.substring(STABLE_PREFIX.length()); }
 635    // remove "beta-" prefix
 636  0 final String BETA_PREFIX = "beta-";
 637  0 if (line.startsWith(BETA_PREFIX)) { line = line.substring(BETA_PREFIX.length()); }
 638    // remove "weekly-" prefix
 639  0 final String WEEKLY_PREFIX = "weekly-";
 640  0 if (line.startsWith(WEEKLY_PREFIX)) { line = line.substring(WEEKLY_PREFIX.length()); }
 641    // if this version string uses the new format with the release at the end, remove it
 642  0 int releasePos = line.indexOf("-r");
 643  0 if (releasePos>=0) { line = line.substring(0, releasePos); }
 644   
 645  0 return new SimpleDateFormat("yyyyMMdd z").parse(line + " GMT");
 646    }
 647    catch (Exception e) { // parse format or whatever problem
 648  0 return null;
 649    }
 650    }
 651   
 652    /** Runnable that calls _cancel. */
 653    protected final Runnable1<WindowEvent> CANCEL = new Runnable1<WindowEvent>() {
 654  0 public void run(WindowEvent e) { closeAction(); }
 655    };
 656   
 657    /** Toggle visibility of this frame. Warning, it behaves like a modal dialog. */
 658  0 public void setVisible(boolean vis) {
 659  0 assert EventQueue.isDispatchThread();
 660  0 validate();
 661  0 if (vis) {
 662  0 _mainFrame.hourglassOn();
 663  0 _mainFrame.installModalWindowAdapter(this, LambdaUtil.NO_OP, CANCEL);
 664    }
 665    else {
 666  0 _mainFrame.removeModalWindowAdapter(this);
 667  0 _mainFrame.hourglassOff();
 668  0 _mainFrame.toFront();
 669    }
 670  0 super.setVisible(vis);
 671    }
 672    }