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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/*******************************************************************************
* Copyright (c) 2006 Elphel, Inc and Excelsior, LLC.
* This file is a part of Eclipse/VDT plug-in.
* Eclipse/VDT plug-in is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* Eclipse/VDT plug-in is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with Eclipse VDT plug-in; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
package com.elphel.vdt.ui.dialogs;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.dialogs.IconAndMessageDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
public class VDTErrorDialog extends IconAndMessageDialog {
private static final String NESTING_INDENT = " ";
private static final int MAX_DETAILS_LINES = 15;
private Button detailsButton;
private String title;
private Text text;
private boolean textCreated = false;
private int displayMask = 0xFFFF;
private IStatus status;
/**
* Creates an error dialog. Note that the dialog will have no visual
* representation (no widgets) until it is told to open.
* <p>
* Normally one should use <code>openError</code> to create and open one
* of these. This constructor is useful only if the error object being
* displayed contains child items <it>and </it> you need to specify a mask
* which will be used to filter the displaying of these children.
* </p>
*
* @param parentShell
* the shell under which to create this dialog
* @param dialogTitle
* the title to use for this dialog, or <code>null</code> to
* indicate that the default title should be used
* @param message
* the message to show in this dialog, or <code>null</code> to
* indicate that the error's message should be shown as the
* primary message
* @param status
* the error to show to the user
* @param displayMask
* the mask to use to filter the displaying of child items, as
* per <code>IStatus.matches</code>
* @see org.eclipse.core.runtime.IStatus#matches(int)
*/
public VDTErrorDialog(Shell parentShell,
String dialogTitle,
IStatus status,
int displayMask)
{
super(parentShell);
if(dialogTitle != null)
this.title = dialogTitle;
else
this.title = JFaceResources.getString("Problem_Occurred");
this.message = status.getMessage();
this.status = status;
this.displayMask = displayMask;
setShellStyle(getShellStyle() | SWT.RESIZE);
}
protected void buttonPressed(int id) {
if (id == IDialogConstants.DETAILS_ID) {
// was the details button pressed?
toggleDetailsArea();
} else {
super.buttonPressed(id);
}
}
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText(title);
}
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent,
IDialogConstants.OK_ID,
IDialogConstants.OK_LABEL,
true);
if (shouldShowDetailsButton())
detailsButton = createButton(parent,
IDialogConstants.DETAILS_ID,
IDialogConstants.SHOW_DETAILS_LABEL,
false);
}
protected Control createDialogArea(Composite parent) {
createMessageArea(parent);
// create a composite with standard margins and spacing
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
layout.numColumns = 2;
composite.setLayout(layout);
GridData childData = new GridData(GridData.FILL_BOTH);
childData.horizontalSpan = 2;
composite.setLayoutData(childData);
composite.setFont(parent.getFont());
return composite;
}
/*
* @see IconAndMessageDialog#createDialogAndButtonArea(Composite)
*/
protected void createDialogAndButtonArea(Composite parent) {
super.createDialogAndButtonArea(parent);
if (this.dialogArea instanceof Composite) {
//Create a label if there are no children to force a smaller layout
Composite dialogComposite = (Composite) dialogArea;
if (dialogComposite.getChildren().length == 0)
new Label(dialogComposite, SWT.NULL);
}
}
protected Image getImage() {
if (status != null) {
if (status.getSeverity() == IStatus.WARNING)
return getWarningImage();
if (status.getSeverity() == IStatus.INFO)
return getInfoImage();
}
//If it was not a warning or an error then return the error image
return getErrorImage();
}
private Text createDropDownText(Composite parent) {
// create the text
text = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
text.setFont(parent.getFont());
// fill the text
populateText(text);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
data.heightHint = Math.min(MAX_DETAILS_LINES, text.getLineCount()) * text.getLineHeight();
data.horizontalSpan = 2;
text.setLayoutData(data);
text.setFont(parent.getFont());
textCreated = true;
return text;
}
/**
* Extends <code>Window.open()</code>. Opens an error dialog to display
* the error. If you specified a mask to filter the displaying of these
* children, the error dialog will only be displayed if there is at least
* one child status matching the mask.
*/
public int open() {
if (shouldDisplay(status, displayMask))
return super.open();
setReturnCode(OK);
return OK;
}
/**
* Opens an error dialog to display the given error. Use this method if the
* error object being displayed does not contain child items, or if you wish
* to display all such items without filtering.
*
* @param parent
* the parent shell of the dialog, or <code>null</code> if none
* @param dialogTitle
* the title to use for this dialog, or <code>null</code> to
* indicate that the default title should be used
* @param message
* the message to show in this dialog, or <code>null</code> to
* indicate that the error's message should be shown as the
* primary message
* @param status
* the error to show to the user
* @return the code of the button that was pressed that resulted in this
* dialog closing. This will be <code>Dialog.OK</code> if the OK
* button was pressed, or <code>Dialog.CANCEL</code> if this
* dialog's close window decoration or the ESC key was used.
*/
public static int openError(Shell parent,
String dialogTitle,
IStatus status)
{
return openError(parent,
dialogTitle,
status,
IStatus.OK |
IStatus.INFO |
IStatus.WARNING |
IStatus.ERROR);
}
/**
* Opens an error dialog to display the given error. Use this method if the
* error object being displayed contains child items <it>and </it> you wish
* to specify a mask which will be used to filter the displaying of these
* children. The error dialog will only be displayed if there is at least
* one child status matching the mask.
*
* @param parentShell
* the parent shell of the dialog, or <code>null</code> if none
* @param title
* the title to use for this dialog, or <code>null</code> to
* indicate that the default title should be used
* @param message
* the message to show in this dialog, or <code>null</code> to
* indicate that the error's message should be shown as the
* primary message
* @param status
* the error to show to the user
* @param displayMask
* the mask to use to filter the displaying of child items, as
* per <code>IStatus.matches</code>
* @return the code of the button that was pressed that resulted in this
* dialog closing. This will be <code>Dialog.OK</code> if the OK
* button was pressed, or <code>Dialog.CANCEL</code> if this
* dialog's close window decoration or the ESC key was used.
* @see org.eclipse.core.runtime.IStatus#matches(int)
*/
public static int openError(Shell parentShell,
String title,
IStatus status,
int displayMask)
{
VDTErrorDialog dialog = new VDTErrorDialog(parentShell,
title,
status,
displayMask);
return dialog.open();
}
private void populateText(Text textToPopulate) {
populateText(textToPopulate, status, 0, false);
}
/**
* Populate the text with the messages from the given status. Traverse the
* children of the status deeply and also traverse CoreExceptions that appear
* in the status.
* @param textToPopulate the text to populate
* @param buildingStatus the status being displayed
* @param nesting the nesting level (increases one level for each level of children)
* @param includeStatus whether to include the buildingStatus in the display or
* just its children
*/
private void populateText(Text textToPopulate,
IStatus buildingStatus,
int nesting,
boolean includeStatus)
{
if (!buildingStatus.matches(displayMask)) {
return;
}
Throwable t = buildingStatus.getException();
boolean isCoreException= t instanceof CoreException;
boolean incrementNesting= false;
String string = "";
if (includeStatus) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < nesting; i++) {
sb.append(NESTING_INDENT);
}
String message = buildingStatus.getMessage();
sb.append(message);
string += sb.toString();
incrementNesting = true;
}
if (!isCoreException && t != null) {
// print the stacktrace in the text field
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
t.printStackTrace(ps);
ps.flush();
baos.flush();
string += baos.toString();
} catch (IOException e) {
}
incrementNesting = true;
}
String oldString = textToPopulate.getText();
textToPopulate.setText(oldString + string);
if (incrementNesting)
nesting++;
// Look for a nested core exception
if (isCoreException) {
CoreException ce = (CoreException)t;
IStatus eStatus = ce.getStatus();
// Only print the exception message if it is not contained in the parent message
if (message == null || message.indexOf(eStatus.getMessage()) == -1) {
populateText(textToPopulate, eStatus, nesting, true);
}
}
// Look for child status
IStatus[] children = buildingStatus.getChildren();
for (int i = 0; i < children.length; i++) {
populateText(textToPopulate, children[i], nesting, true);
}
}
/**
* Returns whether the given status object should be displayed.
*
* @param status
* a status object
* @param mask
* a mask as per <code>IStatus.matches</code>
* @return <code>true</code> if the given status should be displayed, and
* <code>false</code> otherwise
* @see org.eclipse.core.runtime.IStatus#matches(int)
*/
private static boolean shouldDisplay(IStatus status, int mask) {
IStatus[] children = status.getChildren();
if (children == null || children.length == 0) {
return status.matches(mask);
}
for (int i = 0; i < children.length; i++) {
if (children[i].matches(mask))
return true;
}
return false;
}
/**
* Toggles the unfolding of the details area. This is triggered by the user
* pressing the details button.
*/
private void toggleDetailsArea() {
Point windowSize = getShell().getSize();
Point oldSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
if (textCreated) {
text.dispose();
textCreated = false;
detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
} else {
text = createDropDownText((Composite) getContents());
detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
}
Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
getShell()
.setSize(
new Point(windowSize.x, windowSize.y
+ (newSize.y - oldSize.y)));
}
private boolean shouldShowDetailsButton() {
return status.isMultiStatus() || status.getException() != null;
}
}