Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 461   Methods: 19
NCLOC: 336   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DrJavaErrorWindow.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.event.*;
 41    import javax.swing.text.*;
 42    import javax.swing.border.*;
 43    import java.awt.event.*;
 44    import java.awt.*;
 45    import java.util.Map;
 46   
 47    import edu.rice.cs.drjava.DrJava;
 48    import edu.rice.cs.util.UnexpectedException;
 49    import edu.rice.cs.util.StringOps;
 50    import edu.rice.cs.util.swing.BorderlessScrollPane;
 51    import edu.rice.cs.drjava.platform.PlatformFactory;
 52    import edu.rice.cs.plt.lambda.Runnable1;
 53    import edu.rice.cs.plt.lambda.LambdaUtil;
 54    import edu.rice.cs.drjava.config.OptionConstants;
 55    import edu.rice.cs.drjava.config.FileConfiguration;
 56   
 57    /** Displays uncaught exceptions and logged conditions.
 58    * This window is not automatically updated when new errors occur. In the case of errors, we want to
 59    * minimize the effects on the GUI. If we want to see an updated dialog, we can click on the "DrJava Errors"
 60    * button again.
 61    * @version $Id: DrJavaErrorWindow.java 5232 2010-04-24 00:14:05Z mgricken $
 62    */
 63    public class DrJavaErrorWindow extends JDialog {
 64    /** Sourceforge add bug URL */
 65    public static final String SF_ADD_BUG_URL = "http://sourceforge.net/tracker/?func=add&group_id=44253&atid=438935/";
 66   
 67    /** Sourceforge URL */
 68    public static final String SF_LINK_NAME = "http://sourceforge.net/projects/drjava";
 69   
 70    /** information about the error */
 71    private volatile JEditorPane _errorInfo;
 72    /** contains the stack trace */
 73    private final JTextArea _stackTrace;
 74    /** label with index */
 75    private final JLabel _indexLabel;
 76    /** scroll pane for _stackTrace */
 77    private final JScrollPane _stackTraceScroll;
 78    /** compresses the buttonPanel into the east */
 79    private final JPanel _bottomPanel;
 80    /** contains the butons */
 81    private final JPanel _buttonPanel;
 82    /** the button that copies the stack trace to the clipboard */
 83    private final JButton _copyButton;
 84    /** the button that closes this window */
 85    private final JButton _okButton;
 86    /** the button that moves to the next error */
 87    private final JButton _nextButton;
 88    /** the button that moves to the previous error */
 89    private final JButton _prevButton;
 90    /** the button that clears all errors and closes the window */
 91    private final JButton _dismissButton;
 92    /** the number of errors that had occurred */
 93    private volatile int _errorCount;
 94    /** the currently selected error */
 95    private volatile Throwable _error;
 96    /** the currently selected error index */
 97    private volatile int _errorIndex;
 98    /** the parent frame */
 99    private static volatile JFrame _parentFrame = null;
 100    /** true if parent changed since last singleton() call */
 101    private static volatile boolean _parentChanged = true;
 102   
 103    /** Sets the parent frame. */
 104  0 public static void setFrame(JFrame f) { _parentFrame = f; _parentChanged = true; }
 105   
 106    /** Gets the parent frame. */
 107  0 public static JFrame getFrame() { return _parentFrame; }
 108   
 109    /** The singleton instance of this dialog. */
 110    private static volatile DrJavaErrorWindow _singletonInstance;
 111   
 112    /** Returns the singleton instance. Recreates it if necessary. */
 113  0 public static DrJavaErrorWindow singleton() {
 114  0 if (_parentChanged) {
 115  0 synchronized(DrJavaErrorWindow.class) {
 116  0 if (_parentChanged) {
 117  0 _singletonInstance = new DrJavaErrorWindow();
 118  0 _parentChanged = false;
 119    }
 120    }
 121    }
 122  0 return _singletonInstance;
 123    }
 124   
 125    /** Creates a window to graphically display the errors that have occurred in the code of DrJava. */
 126  0 private DrJavaErrorWindow() {
 127  0 super(_parentFrame, "DrJava Errors");
 128   
 129  0 this.setSize(600,400);
 130   
 131    // If we set this pane to be of type text/rtf, it wraps based on words
 132    // as opposed to based on characters.
 133  0 _stackTrace = new JTextArea();
 134  0 _stackTrace.setEditable(false);
 135   
 136  0 _prevButton = new JButton(_prevAction);
 137  0 _nextButton = new JButton(_nextAction);
 138  0 _copyButton = new JButton(_copyAction);
 139  0 _dismissButton = new JButton(_dismissAction);
 140  0 _okButton = new JButton(_okAction);
 141   
 142  0 _bottomPanel = new JPanel(new BorderLayout());
 143  0 _buttonPanel = new JPanel();
 144  0 _buttonPanel.add(_prevButton);
 145  0 _buttonPanel.add(_nextButton);
 146  0 _buttonPanel.add(_copyButton);
 147  0 _buttonPanel.add(_dismissButton);
 148  0 _buttonPanel.add(_okButton);
 149  0 _indexLabel = new JLabel();
 150  0 _bottomPanel.add(_indexLabel, BorderLayout.CENTER);
 151  0 _bottomPanel.add(_buttonPanel, BorderLayout.EAST);
 152   
 153  0 _stackTraceScroll = new BorderlessScrollPane(_stackTrace,
 154    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
 155    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
 156  0 _errorInfo = new JEditorPane("text/html", HEADER_HTML+NO_ERRORS_HTML);
 157  0 _errorInfo.setEditable(false);
 158  0 _errorInfo.setBackground(getContentPane().getBackground());
 159  0 final JPanel cp = new JPanel(new BorderLayout(5,5));
 160  0 cp.setBorder(new EmptyBorder(5,5,5,5));
 161  0 setContentPane(cp);
 162  0 cp.add(_errorInfo, BorderLayout.NORTH);
 163  0 cp.add(_stackTraceScroll, BorderLayout.CENTER);
 164  0 cp.add(_bottomPanel, BorderLayout.SOUTH);
 165  0 getRootPane().setDefaultButton(_okButton);
 166  0 init();
 167    }
 168   
 169    protected WindowAdapter _windowListener = new WindowAdapter() {
 170  0 public void windowDeactivated(WindowEvent we) {
 171  0 DrJavaErrorWindow.this.toFront();
 172    }
 173  0 public void windowClosing(WindowEvent we) {
 174  0 DrJavaErrorWindow.this.dispose();
 175  0 if (DrJavaErrorHandler.getButton() == null) { System.exit(1); }
 176    }
 177    };
 178   
 179    /** Lambda that calls _cancel. */
 180    protected final Runnable1<WindowEvent> CANCEL = new Runnable1<WindowEvent>() {
 181  0 public void run(WindowEvent e) {
 182  0 if (DrJavaErrorHandler.getButton() == null) { System.exit(1); }
 183    }
 184    };
 185   
 186    /** Validates before changing visibility. Only runs in the event thread.
 187    * @param vis true if frame should be shown, false if it should be hidden.
 188    */
 189  0 public void setVisible(boolean vis) {
 190  0 assert EventQueue.isDispatchThread();
 191  0 validate();
 192  0 if (vis) {
 193  0 init();
 194  0 if (_parentFrame != null) {
 195  0 edu.rice.cs.drjava.DrJavaRoot.installModalWindowAdapter(this, LambdaUtil.NO_OP, CANCEL);
 196    }
 197  0 toFront();
 198    }
 199    else {
 200  0 if (_parentFrame != null) {
 201  0 edu.rice.cs.drjava.DrJavaRoot.removeModalWindowAdapter(this);
 202  0 _parentFrame.toFront();
 203    }
 204    }
 205  0 super.setVisible(vis);
 206    }
 207   
 208    /** Initialize the dialog. */
 209  0 private void init() {
 210  0 _errorCount = DrJavaErrorHandler.getErrorCount();
 211  0 if (_errorCount > 0) {
 212  0 _error = DrJavaErrorHandler.getError(0);
 213  0 _errorIndex = 0;
 214    }
 215    else {
 216  0 _error = null;
 217  0 _errorIndex = -1;
 218    }
 219  0 _prevAction.setEnabled(false);
 220  0 _nextAction.setEnabled(_errorCount>1);
 221  0 _dismissAction.setEnabled(_errorCount > 0);
 222  0 _copyAction.setEnabled(_errorCount > 0);
 223  0 updateErrorInfo();
 224    }
 225   
 226    /** Update the buttons and text area after next or previous. */
 227  0 private void updateErrorInfo() {
 228  0 getContentPane().remove(_errorInfo);
 229  0 if (_error != null) {
 230  0 final StringBuilder b = new StringBuilder();
 231  0 if (_error instanceof DrJavaErrorHandler.LoggedCondition) {
 232  0 b.append("Logged condition: ");
 233  0 b.append(_error.getMessage());
 234  0 b.append('\n');
 235  0 boolean first = true;
 236  0 for (StackTraceElement ste: _error.getStackTrace()) {
 237  0 if (first) { first = false; continue; /* skip first frame, that's the log method itself */ }
 238  0 b.append("\tat ");
 239  0 b.append(ste);
 240  0 b.append('\n');
 241    }
 242    }
 243    else {
 244  0 b.append(StringOps.getStackTrace(_error));
 245  0 if (_error instanceof UnexpectedException) {
 246  0 Throwable t = ((UnexpectedException)_error).getCause();
 247  0 b.append("\nCaused by:\n");
 248  0 b.append(StringOps.getStackTrace(t));
 249    }
 250    }
 251   
 252  0 b.append("\n\n");
 253  0 b.append(getSystemAndDrJavaInfo());
 254   
 255  0 _stackTrace.setText(b.toString());
 256  0 _stackTrace.setCaretPosition(0);
 257   
 258  0 final StringBuilder b2 = new StringBuilder();
 259  0 b2.append(HEADER_HTML);
 260  0 b2.append(_errorCount);
 261  0 b2.append(" error");
 262  0 b2.append(((_errorCount>1)?"s":""));
 263  0 b2.append(" occured!<br>");
 264  0 b2.append(ERRORS_FOOTER_HTML);
 265  0 _errorInfo = new JEditorPane("text/html", b2.toString());
 266  0 _errorInfo.addHyperlinkListener(new HyperlinkListener() {
 267  0 public void hyperlinkUpdate(HyperlinkEvent e) {
 268  0 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
 269  0 try {
 270  0 PlatformFactory.ONLY.openURL(e.getURL());
 271    } catch(Exception ex) { /* ignore, just not open web page */ }
 272    }
 273    }
 274    });
 275  0 _errorInfo.setEditable(false);
 276  0 _errorInfo.setBackground(getContentPane().getBackground());
 277  0 _indexLabel.setText("Error " + (_errorIndex+1) + " of " + (_errorCount));
 278    }
 279    else {
 280  0 _errorInfo = new JEditorPane("text/html", HEADER_HTML+NO_ERRORS_HTML);
 281  0 _errorInfo.addHyperlinkListener(new HyperlinkListener() {
 282  0 public void hyperlinkUpdate(HyperlinkEvent e) {
 283  0 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
 284  0 try {
 285  0 PlatformFactory.ONLY.openURL(e.getURL());
 286    } catch(Exception ex) { /* ignore, just not open web page */ }
 287    }
 288    }
 289    });
 290  0 _errorInfo.setEditable(false);
 291  0 _errorInfo.setBackground(getContentPane().getBackground());
 292  0 _stackTrace.setText("");
 293  0 _indexLabel.setText("");
 294    }
 295  0 getContentPane().add(_errorInfo, BorderLayout.NORTH);
 296  0 validate();
 297    }
 298   
 299    /** Return a string with the system properties, the DrJava configuration file contents, and
 300    * information about memory. The data is anonymized.
 301    * @return information string */
 302  0 public static String getSystemAndDrJavaInfo() {
 303  0 final StringBuilder b = new StringBuilder();
 304  0 b.append("System Properties:\n");
 305  0 b.append("DrJava Version ");
 306  0 b.append(edu.rice.cs.drjava.Version.getVersionString());
 307  0 FileConfiguration config = DrJava.getConfig();
 308  0 if (config!=null) {
 309  0 String customDrJavaJarVersionSuffix = config.getSetting(OptionConstants.CUSTOM_DRJAVA_JAR_VERSION_SUFFIX);
 310  0 if (customDrJavaJarVersionSuffix.length()>0) {
 311  0 b.append(" with ");
 312  0 b.append(customDrJavaJarVersionSuffix);
 313    }
 314    }
 315  0 b.append('\n');
 316  0 b.append("DrJava Build Time ");
 317  0 b.append(edu.rice.cs.drjava.Version.getBuildTimeString());
 318  0 b.append("\n\n");
 319  0 java.util.Properties props = System.getProperties();
 320    // int size = props.size();
 321  0 for (Map.Entry<Object, Object> entry : props.entrySet()) {
 322  0 b.append(entry.getKey());
 323  0 b.append(" = ");
 324  0 if (entry.getKey().equals("line.separator")) {
 325  0 b.append("\"");
 326  0 String ls = (String)entry.getValue();
 327  0 for(int i = 0; i < ls.length(); ++i) {
 328  0 int ch = ls.charAt(i);
 329  0 b.append("\\u");
 330  0 String hexString = "0000" + Integer.toHexString(ch);
 331  0 b.append(hexString.substring(hexString.length()-4));
 332    }
 333  0 b.append("\"");
 334    }
 335    else {
 336  0 b.append(entry.getValue());
 337    }
 338  0 b.append('\n');
 339    }
 340  0 b.append('\n');
 341  0 b.append("DrJava configuration file\n");
 342  0 b.append(DrJava.getConfig().toString());
 343   
 344  0 b.append("\n\nUsed memory: about ");
 345  0 b.append(StringOps.memSizeToString(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));
 346  0 b.append("\nFree memory: about ");
 347  0 b.append(StringOps.memSizeToString(Runtime.getRuntime().freeMemory()));
 348  0 b.append("\nTotal memory: about ");
 349  0 b.append(StringOps.memSizeToString(Runtime.getRuntime().totalMemory()));
 350  0 b.append("\nTotal memory can expand to: about ");
 351  0 b.append(StringOps.memSizeToString(Runtime.getRuntime().maxMemory()));
 352  0 b.append("\n\nNumber of processors/cores: ");
 353  0 b.append(Runtime.getRuntime().availableProcessors());
 354  0 b.append("\n\n");
 355  0 b.append("Compiler Discovery Log:\n");
 356  0 b.append(edu.rice.cs.drjava.model.JarJDKToolsLibrary.LOG_STRINGWRITER.toString());
 357  0 b.append("\n\n");
 358   
 359    // filter out user.dir, user.home and user.name
 360  0 String infoText = b.toString();
 361   
 362  0 String userHome = System.getProperty("user.home");
 363  0 String anonUserHome = "<anonymized user.home>";
 364  0 infoText = replaceString(infoText, userHome, anonUserHome);
 365   
 366  0 String userDir = System.getProperty("user.dir");
 367  0 String anonUserDir = "<anonymized user.dir>";
 368  0 infoText = replaceString(infoText, userDir, anonUserDir);
 369   
 370  0 String userName = System.getProperty("user.name");
 371  0 String anonUserName = "<anonymized user.name>";
 372  0 infoText = replaceString(infoText, userName, anonUserName);
 373   
 374  0 return infoText;
 375    }
 376   
 377    /* Close the window. */
 378    private final Action _okAction = new AbstractAction("OK") {
 379  0 public void actionPerformed(ActionEvent e) {
 380  0 DrJavaErrorWindow.this.dispose();
 381  0 if (DrJavaErrorHandler.getButton() == null) { System.exit(1); }
 382    }
 383    };
 384   
 385    /* Go to the previous error. */
 386    private final Action _prevAction = new AbstractAction("Previous") {
 387  0 public void actionPerformed(ActionEvent e) {
 388  0 if (_errorIndex > 0) {
 389  0 --_errorIndex;
 390  0 _error = DrJavaErrorHandler.getError(_errorIndex);
 391  0 if (_errorIndex == 0) { setEnabled(false); }
 392  0 if (_errorCount>1) { _nextAction.setEnabled(true); }
 393  0 updateErrorInfo();
 394    }
 395    }
 396    };
 397   
 398    /** Replaces all occurrences of orig in text with repl. */
 399  0 private static String replaceString(String text, String orig, String repl) {
 400  0 int pos = 0;
 401  0 while((pos=text.indexOf(orig,pos)) >= 0) {
 402    // found occurrence at pos
 403  0 text = text.substring(0,pos) + repl + text.substring(pos+orig.length(), text.length());
 404    }
 405  0 return text;
 406    }
 407   
 408    /** Go to the next error. */
 409    private final Action _nextAction = new AbstractAction("Next") {
 410  0 public void actionPerformed(ActionEvent e) {
 411  0 if (_errorIndex < _errorCount-1) {
 412  0 ++_errorIndex;
 413  0 _error = DrJavaErrorHandler.getError(_errorIndex);
 414  0 if (_errorIndex == _errorCount-1) { setEnabled(false); }
 415  0 if (_errorCount>1) { _prevAction.setEnabled(true); }
 416  0 updateErrorInfo();
 417    }
 418    }
 419    };
 420   
 421    /** Dismiss all errors and close the window. */
 422    private Action _dismissAction = new AbstractAction("Dismiss") {
 423  0 public void actionPerformed(ActionEvent e) {
 424  0 DrJavaErrorHandler.clearErrors();
 425  0 _errorCount = 0;
 426  0 _error = null;
 427  0 _errorIndex = -1;
 428  0 setEnabled(false);
 429  0 _prevAction.setEnabled(false);
 430  0 _nextAction.setEnabled(false);
 431  0 _copyAction.setEnabled(false);
 432  0 updateErrorInfo();
 433  0 JButton errorsButton = DrJavaErrorHandler.getButton();
 434  0 if (errorsButton != null) { errorsButton.setVisible(false); }
 435  0 _okAction.actionPerformed(e);
 436    }
 437    };
 438   
 439    /** Copy currently selected error to clip board. */
 440    private Action _copyAction = new AbstractAction("Copy This Error") {
 441  0 public void actionPerformed(ActionEvent e) {
 442  0 _stackTrace.grabFocus();
 443  0 _stackTrace.getActionMap().get(DefaultEditorKit.selectAllAction).actionPerformed(e);
 444  0 _stackTrace.getActionMap().get(DefaultEditorKit.copyAction).actionPerformed(e);
 445    }
 446    };
 447   
 448    /** Canned message for the user.
 449    */
 450    private static final String HEADER_HTML =
 451    "<html><font size=\"-1\" face=\"sans-serif, Arial, Helvetica, Geneva\"><b>";
 452    private static final String ERRORS_FOOTER_HTML =
 453    "Please submit a bug report containing the information below " +
 454    "and an account of the actions that caused the bug (if known) to " +
 455    "<a href=\"" + SF_ADD_BUG_URL + "\"><b>" + SF_LINK_NAME + "</b></a>.<br>" +
 456    "You may wish to save all your work and restart DrJava.<br>" +
 457    "Thanks for your help in making DrJava better!</b></font></p></html>";
 458    private static final String NO_ERRORS_HTML =
 459    "No errors occurred!<br>" +
 460    "Thanks for using DrJava!</b></font></p></html>";
 461    }