blob: 9346dfb09d3387a0cc63fb7d9c6dc33b76b780fd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Dirk Fauth and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.ui;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* Dialog that can be used to show an error with an additional stacktrace.
*
* @since 1.5
*/
public class ExceptionDialog extends Dialog {
private static final Log LOG = LogFactory.getLog(ExceptionDialog.class);
private String title;
private String message;
private Exception exception;
private Button detailsButton;
private Text exceptionText;
private boolean exceptionAreaCreated = false;
protected ExceptionDialog(Shell parentShell, String title, String message, Exception exception) {
super(parentShell);
this.title = title;
this.message = message != null ? message : exception.getLocalizedMessage();
this.exception = exception;
}
@Override
protected Control createDialogArea(Composite parent) {
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);
GridDataFactory.fillDefaults().grab(true, false).applyTo(composite);
createMessageArea(composite);
return composite;
}
protected Control createMessageArea(Composite composite) {
// create composite
// create image
Image image = getParentShell().getDisplay().getSystemImage(SWT.ICON_ERROR);
Label imageLabel = new Label(composite, SWT.NULL);
image.setBackground(imageLabel.getBackground());
imageLabel.setImage(image);
GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.BEGINNING).applyTo(imageLabel);
// create message
if (this.message != null) {
Label messageLabel = new Label(composite, SWT.WRAP);
messageLabel.setText(this.message);
GridDataFactory
.fillDefaults()
.align(SWT.FILL, SWT.CENTER)
.grab(true, false)
.hint(convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH), SWT.DEFAULT)
.applyTo(messageLabel);
}
return composite;
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
// create OK and Details buttons
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
if (this.exception != null) {
this.detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false);
}
}
@Override
protected void buttonPressed(int id) {
if (id == IDialogConstants.DETAILS_ID) {
// was the details button pressed?
toggleDetailsArea();
} else {
super.buttonPressed(id);
}
}
private void toggleDetailsArea() {
boolean opened = false;
Point windowSize = getShell().getSize();
if (this.exceptionAreaCreated) {
this.exceptionText.dispose();
this.exceptionAreaCreated = false;
this.detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
opened = false;
} else {
this.exceptionText = createExceptionText((Composite) getContents());
this.detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
getContents().getShell().layout();
opened = true;
}
Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
int diffY = newSize.y - windowSize.y;
// increase the dialog height if details were opened and such increase
// is necessary
// decrease the dialog height if details were closed and empty space
// appeared
if ((opened && diffY > 0) || (!opened && diffY < 0)) {
getShell().setSize(new Point(windowSize.x, windowSize.y + (diffY)));
}
}
private Text createExceptionText(Composite parent) {
Text exceptionText = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
GridDataFactory
.fillDefaults()
.grab(true, true)
.span(2, 1)
.applyTo(exceptionText);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
this.exception.printStackTrace(pw);
exceptionText.setText(sw.toString());
} finally {
try {
sw.close();
pw.close();
} catch (IOException e) {
LOG.error("Closing stream failed", e); //$NON-NLS-1$
}
}
this.exceptionAreaCreated = true;
return exceptionText;
}
/**
* Opens an error dialog to display the given error.
*
* @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 exception
* 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 open(Shell parentShell, String title, Exception exception) {
return open(parentShell, title, exception.getLocalizedMessage(), exception);
}
/**
* Opens an error dialog to display the given error.
*
* @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 exception
* 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 open(Shell parentShell, String title, String message, Exception exception) {
ExceptionDialog dialog = new ExceptionDialog(parentShell, title, message, exception);
return dialog.open();
}
@Override
protected boolean isResizable() {
return true;
}
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(this.title);
newShell.setImage(getParentShell().getDisplay().getSystemImage(SWT.ICON_ERROR));
}
}