|
1 |
| |
|
2 |
| |
|
3 |
| |
|
4 |
| |
|
5 |
| |
|
6 |
| |
|
7 |
| |
|
8 |
| |
|
9 |
| |
|
10 |
| |
|
11 |
| |
|
12 |
| |
|
13 |
| |
|
14 |
| |
|
15 |
| |
|
16 |
| |
|
17 |
| |
|
18 |
| |
|
19 |
| |
|
20 |
| |
|
21 |
| |
|
22 |
| |
|
23 |
| |
|
24 |
| |
|
25 |
| |
|
26 |
| |
|
27 |
| |
|
28 |
| |
|
29 |
| |
|
30 |
| |
|
31 |
| |
|
32 |
| |
|
33 |
| |
|
34 |
| |
|
35 |
| |
|
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 |
| |
|
58 |
| |
|
59 |
| |
|
60 |
| |
|
61 |
| |
|
62 |
| |
|
63 |
| public class DrJavaErrorWindow extends JDialog { |
|
64 |
| |
|
65 |
| public static final String SF_ADD_BUG_URL = "http://sourceforge.net/tracker/?func=add&group_id=44253&atid=438935/"; |
|
66 |
| |
|
67 |
| |
|
68 |
| public static final String SF_LINK_NAME = "http://sourceforge.net/projects/drjava"; |
|
69 |
| |
|
70 |
| |
|
71 |
| private volatile JEditorPane _errorInfo; |
|
72 |
| |
|
73 |
| private final JTextArea _stackTrace; |
|
74 |
| |
|
75 |
| private final JLabel _indexLabel; |
|
76 |
| |
|
77 |
| private final JScrollPane _stackTraceScroll; |
|
78 |
| |
|
79 |
| private final JPanel _bottomPanel; |
|
80 |
| |
|
81 |
| private final JPanel _buttonPanel; |
|
82 |
| |
|
83 |
| private final JButton _copyButton; |
|
84 |
| |
|
85 |
| private final JButton _okButton; |
|
86 |
| |
|
87 |
| private final JButton _nextButton; |
|
88 |
| |
|
89 |
| private final JButton _prevButton; |
|
90 |
| |
|
91 |
| private final JButton _dismissButton; |
|
92 |
| |
|
93 |
| private volatile int _errorCount; |
|
94 |
| |
|
95 |
| private volatile Throwable _error; |
|
96 |
| |
|
97 |
| private volatile int _errorIndex; |
|
98 |
| |
|
99 |
| private static volatile JFrame _parentFrame = null; |
|
100 |
| |
|
101 |
| private static volatile boolean _parentChanged = true; |
|
102 |
| |
|
103 |
| |
|
104 |
0
| public static void setFrame(JFrame f) { _parentFrame = f; _parentChanged = true; }
|
|
105 |
| |
|
106 |
| |
|
107 |
0
| public static JFrame getFrame() { return _parentFrame; }
|
|
108 |
| |
|
109 |
| |
|
110 |
| private static volatile DrJavaErrorWindow _singletonInstance; |
|
111 |
| |
|
112 |
| |
|
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 |
| |
|
126 |
0
| private DrJavaErrorWindow() {
|
|
127 |
0
| super(_parentFrame, "DrJava Errors");
|
|
128 |
| |
|
129 |
0
| this.setSize(600,400);
|
|
130 |
| |
|
131 |
| |
|
132 |
| |
|
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 |
| |
|
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 |
| |
|
187 |
| |
|
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 |
| |
|
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 |
| |
|
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; }
|
|
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) { } |
|
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) { } |
|
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 |
| |
|
300 |
| |
|
301 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| |
|
403 |
0
| text = text.substring(0,pos) + repl + text.substring(pos+orig.length(), text.length());
|
|
404 |
| } |
|
405 |
0
| return text;
|
|
406 |
| } |
|
407 |
| |
|
408 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| |
|
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 |
| } |