Commit | Line | Data |
---|---|---|
e23ea538 KL |
1 | /* |
2 | * Jexer - Java Text User Interface | |
3 | * | |
4 | * The MIT License (MIT) | |
5 | * | |
6 | * Copyright (C) 2019 Kevin Lamonte | |
7 | * | |
8 | * Permission is hereby granted, free of charge, to any person obtaining a | |
9 | * copy of this software and associated documentation files (the "Software"), | |
10 | * to deal in the Software without restriction, including without limitation | |
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
12 | * and/or sell copies of the Software, and to permit persons to whom the | |
13 | * Software is furnished to do so, subject to the following conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice shall be included in | |
16 | * all copies or substantial portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
21 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
24 | * DEALINGS IN THE SOFTWARE. | |
25 | * | |
26 | * @author Kevin Lamonte [kevin.lamonte@gmail.com] | |
27 | * @version 1 | |
28 | */ | |
29 | package jexer; | |
30 | ||
31 | import java.io.FileWriter; | |
32 | import java.io.IOException; | |
33 | import java.io.PrintWriter; | |
34 | import java.text.MessageFormat; | |
35 | import java.util.ArrayList; | |
36 | import java.util.Date; | |
37 | import java.util.ResourceBundle; | |
38 | ||
39 | import jexer.bits.CellAttributes; | |
40 | ||
41 | /** | |
42 | * TExceptionDialog displays an exception and its stack trace to the user, | |
43 | * and provides a means to save a troubleshooting report for support. | |
44 | */ | |
45 | public class TExceptionDialog extends TWindow { | |
46 | ||
47 | /** | |
48 | * Translated strings. | |
49 | */ | |
50 | private static ResourceBundle i18n = ResourceBundle.getBundle(TExceptionDialog.class.getName()); | |
51 | ||
52 | // ------------------------------------------------------------------------ | |
53 | // Constants -------------------------------------------------------------- | |
54 | // ------------------------------------------------------------------------ | |
55 | ||
56 | // ------------------------------------------------------------------------ | |
57 | // Variables -------------------------------------------------------------- | |
58 | // ------------------------------------------------------------------------ | |
59 | ||
60 | /** | |
61 | * The exception. We will actually make it Throwable, for the unlikely | |
62 | * event we catch an Error rather than an Exception. | |
63 | */ | |
64 | private Throwable exception; | |
65 | ||
66 | /** | |
67 | * The exception's stack trace. | |
68 | */ | |
69 | private TList stackTrace; | |
70 | ||
71 | // ------------------------------------------------------------------------ | |
72 | // Constructors ----------------------------------------------------------- | |
73 | // ------------------------------------------------------------------------ | |
74 | ||
75 | /** | |
76 | * Public constructor. | |
77 | * | |
78 | * @param application TApplication that manages this window | |
79 | * @param exception the exception to display | |
80 | */ | |
81 | public TExceptionDialog(final TApplication application, | |
82 | final Throwable exception) { | |
83 | ||
84 | super(application, i18n.getString("windowTitle"), | |
85 | 1, 1, 70, 20, CENTERED | MODAL); | |
86 | ||
87 | this.exception = exception; | |
88 | ||
89 | addLabel(i18n.getString("captionLine1"), 1, 1, | |
90 | "twindow.background.modal"); | |
91 | addLabel(i18n.getString("captionLine2"), 1, 2, | |
92 | "twindow.background.modal"); | |
93 | addLabel(i18n.getString("captionLine3"), 1, 3, | |
94 | "twindow.background.modal"); | |
95 | addLabel(i18n.getString("captionLine4"), 1, 4, | |
96 | "twindow.background.modal"); | |
97 | ||
98 | addLabel(MessageFormat.format(i18n.getString("exceptionString"), | |
99 | exception.getClass().getName(), exception.getMessage()), | |
100 | 2, 6, "ttext", false); | |
101 | ||
102 | ArrayList<String> stackTraceStrings = new ArrayList<String>(); | |
103 | StackTraceElement [] stack = exception.getStackTrace(); | |
104 | for (int i = 0; i < stack.length; i++) { | |
105 | stackTraceStrings.add(stack[i].toString()); | |
106 | } | |
107 | stackTrace = addList(stackTraceStrings, 2, 7, getWidth() - 6, 8); | |
108 | ||
109 | // Buttons | |
110 | addButton(i18n.getString("saveButton"), 19, getHeight() - 4, | |
111 | new TAction() { | |
112 | public void DO() { | |
113 | saveToFile(); | |
114 | } | |
115 | }); | |
116 | ||
117 | TButton closeButton = addButton(i18n.getString("closeButton"), | |
118 | 35, getHeight() - 4, | |
119 | new TAction() { | |
120 | public void DO() { | |
121 | // Don't do anything, just close the window. | |
122 | TExceptionDialog.this.close(); | |
123 | } | |
124 | }); | |
125 | ||
126 | // Save this for last: make the close button default action. | |
127 | activate(closeButton); | |
128 | } | |
129 | ||
130 | // ------------------------------------------------------------------------ | |
131 | // TWindow ---------------------------------------------------------------- | |
132 | // ------------------------------------------------------------------------ | |
133 | ||
134 | /** | |
135 | * Draw the exception message background. | |
136 | */ | |
137 | @Override | |
138 | public void draw() { | |
139 | // Draw window and border. | |
140 | super.draw(); | |
141 | ||
142 | CellAttributes boxColor = getTheme().getColor("ttext"); | |
143 | hLineXY(3, 7, getWidth() - 6, ' ', boxColor); | |
144 | } | |
145 | ||
146 | // ------------------------------------------------------------------------ | |
147 | // TExceptionDialog ------------------------------------------------------- | |
148 | // ------------------------------------------------------------------------ | |
149 | ||
150 | /** | |
151 | * Save a troubleshooting report to file. Note that we do NOT translate | |
152 | * the strings within the error report. | |
153 | */ | |
154 | private void saveToFile() { | |
155 | // Prompt for filename. | |
156 | PrintWriter writer = null; | |
157 | try { | |
158 | String filename = fileSaveBox("."); | |
159 | if (filename == null) { | |
160 | // User cancelled, bail out. | |
161 | return; | |
162 | } | |
163 | writer = new PrintWriter(new FileWriter(filename)); | |
164 | writer.write("Date: " + new Date(System.currentTimeMillis()) | |
165 | + "\n"); | |
166 | ||
167 | // System properties | |
168 | writer.write("System properties:\n"); | |
169 | writer.write("-----------------------------------\n"); | |
170 | System.getProperties().store(writer, null); | |
171 | writer.write("-----------------------------------\n"); | |
172 | writer.write("\n"); | |
173 | ||
174 | // The exception we caught | |
175 | writer.write("Caught exception:\n"); | |
176 | writer.write("-----------------------------------\n"); | |
177 | exception.printStackTrace(writer); | |
178 | writer.write("-----------------------------------\n"); | |
179 | writer.write("\n"); | |
180 | // The exception's cause, if it was set | |
181 | if (exception.getCause() != null) { | |
182 | writer.write("Caught exception's cause:\n"); | |
183 | writer.write("-----------------------------------\n"); | |
184 | exception.getCause().printStackTrace(writer); | |
185 | writer.write("-----------------------------------\n"); | |
186 | } | |
187 | writer.write("\n"); | |
188 | ||
189 | // The UI stack trace | |
190 | writer.write("UI stack trace:\n"); | |
191 | writer.write("-----------------------------------\n"); | |
192 | (new Throwable("UI Thread")).printStackTrace(writer); | |
193 | writer.write("-----------------------------------\n"); | |
194 | writer.write("\n"); | |
195 | writer.close(); | |
196 | } catch (IOException e) { | |
197 | messageBox(i18n.getString("errorDialogTitle"), | |
198 | MessageFormat.format(i18n. | |
199 | getString("errorSavingFile"), e.getMessage())); | |
200 | } finally { | |
201 | if (writer != null) { | |
202 | writer.close(); | |
203 | writer = null; | |
204 | } | |
205 | } | |
206 | } | |
207 | } |