/* * This file is part of ImageExport. * * ImageExport 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 3 of the License, or * (at your option) any later version. * * ImageExport 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 ImageExport. If not, see <http://www.gnu.org/licenses/>. */ package nl.utwente.ce.imageexport; import java.io.PrintWriter; import java.io.StringWriter; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IconAndMessageDialog; import org.eclipse.jface.resource.JFaceResources; 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.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; /** * <p> * Class that shows an exception in a Eclipse {@link IconAndMessageDialog}. * </p> * <p> * This class is loosely based on {@link org.eclipse.jface.dialogs.ErrorDialog ErrorDialog} * </p> */ public class ExceptionErrorDialog extends IconAndMessageDialog { /** The Details button. */ private Button detailsButton; /** The title of the dialog. */ private String title; /** The SWT list control that displays the error details. */ private Text text; /** Indicates whether the error details viewer is currently created. */ private boolean listCreated = false; /** The status object. */ private IStatus status; /** * @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 */ public ExceptionErrorDialog(Shell parentShell, String dialogTitle, String message, IStatus status) { super(parentShell); this.title = dialogTitle == null ? JFaceResources.getString("Problem_Occurred") : //$NON-NLS-1$ dialogTitle; this.message = message == null ? status.getMessage() : JFaceResources.format( "Reason", new Object[] { message, status.getMessage() }); //$NON-NLS-1$ this.status = status; } @Override protected void buttonPressed(int id) { if (id == IDialogConstants.DETAILS_ID) { // Details button got pressed toggleDetailsArea(); } else { super.buttonPressed(id); } } @Override protected void configureShell(Shell shell) { super.configureShell(shell); shell.setText(title); } @Override protected void createButtonsForButtonBar(Composite parent) { // create OK and Details buttons createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false); } /** Create the area for extra error support information. */ private void createSupportArea(Composite parent) { Composite supportArea = new Composite(parent, SWT.NONE); GridData supportData = new GridData(SWT.FILL, SWT.FILL, true, true); supportData.verticalSpan = 3; supportArea.setLayoutData(supportData); if (supportArea.getLayout() == null) { GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; supportArea.setLayout(layout); // Give it a default layout if one isn't set } } @Override protected Control createDialogArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); createMessageArea(composite); createSupportArea(parent); 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; childData.grabExcessVerticalSpace = false; composite.setLayoutData(childData); composite.setFont(parent.getFont()); return composite; } @Override 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); } } } @Override 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 info then return the error image return getErrorImage(); } /** * Create this dialog's drop-down text component. The text is displayed after the user presses details button. It is * developer responsibility to display details button if and only if there is some content on drop down list. The * visibility of the details button is controlled by {@link #shouldShowDetailsButton()}, which should also be * overridden together with this method. * * @param parent the parent composite * @return the drop-down list component */ protected Text createDropDownText(Composite parent) { text = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); // fill the list populateList(text, status); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL); data.horizontalSpan = 2; text.setLayoutData(data); text.setFont(parent.getFont()); text.setEditable(false); listCreated = true; return text; } /** * 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 status the error to show to the user */ public static void openError(Shell parentShell, String title, String message, IStatus status) { ExceptionErrorDialog dialog = new ExceptionErrorDialog(parentShell, title, message, status); dialog.open(); } /** * Populate the list with the messages from the given status. Traverse the children of the status deeply and also * traverse CoreExceptions that appear in the status. * * @param listToPopulate the list to populate * @param buildingStatus the status being displayed */ private void populateList(Text listToPopulate, IStatus buildingStatus) { Throwable t = buildingStatus.getException(); // Include low-level exception message StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); String message = sw.getBuffer().toString(); if (message == null) { message = t.toString(); } listToPopulate.append(message); } /** 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 (listCreated) { text.dispose(); listCreated = false; detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL); } else { text = createDropDownText((Composite) getContents()); detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); getContents().getShell().layout(); } Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); getShell().setSize(new Point(windowSize.x, windowSize.y + (newSize.y - oldSize.y))); } /** * Show the details portion of the dialog if it is not already visible. This method will only work when it is * invoked after the control of the dialog has been set. In other words, after the <code>createContents</code> * method has been invoked and has returned the control for the content area of the dialog. Invoking the method * before the content area has been set or after the dialog has been disposed will have no effect. * * @since 3.1 */ protected final void showDetailsArea() { if (!listCreated) { Control control = getContents(); if (control != null && !control.isDisposed()) { toggleDetailsArea(); } } } protected boolean isResizable() { return true; } }