Add 'src/jexer/' from commit 'cf01c92f5809a0732409e280fb0f32f27393618d'
[fanfix.git] / src / jexer / TExceptionDialog.java
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 final 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 }