org.nightlabs.base.ui.exceptionhandler.DefaultErrorDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.nightlabs.base.ui.exceptionhandler.DefaultErrorDialog.java

Source

/* *****************************************************************************
 * org.nightlabs.base.ui - NightLabs Eclipse utilities                            *
 * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org                    *
 *                                                                             *
 * This library is free software; you can redistribute it and/or               *
 * modify it under the terms of the GNU Lesser General Public                  *
 * License as published by the Free Software Foundation; either                *
 * version 2.1 of the License, or (at your option) any later version.          *
 *                                                                             *
 * This library 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           *
 * Lesser General Public License for more details.                             *
 *                                                                             *
 * You should have received a copy of the GNU Lesser General Public            *
 * License along with this library; if not, write to the                       *
 *     Free Software Foundation, Inc.,                                         *
 *     51 Franklin St, Fifth Floor,                                            *
 *     Boston, MA  02110-1301  USA                                             *
 *                                                                             *
 * Or get it online :                                                          *
 *     http://www.gnu.org/copyleft/lesser.html                                 *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/

package org.nightlabs.base.ui.exceptionhandler;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.nightlabs.base.ui.exceptionhandler.errorreport.ErrorReport;
import org.nightlabs.base.ui.exceptionhandler.errorreport.ErrorReportWizardDialog;
import org.nightlabs.base.ui.resource.Messages;
import org.nightlabs.base.ui.util.RCPUtil;
import org.nightlabs.eclipse.compatibility.CompatibleDialogConstants;

/**
 * The default error dialog implementation. Error dialogs should be opened
 * by calling one of the <code>showError</code> methods in {@link ErrorDialogFactory}.
 * This error dialog implementation is capable of handling multiple errors in
 * one dialog. It registers itsself in {@link ErrorDialogFactory} to do so.
 *
 * @author Marc Klinger - marc[at]nightlabs[dot]de
 * @author Tobias Langner <!-- tobias[dot]langner[at]nightlabs[dot]de -->
 */
public class DefaultErrorDialog extends MessageDialog implements IErrorDialog {
    private static final Logger logger = Logger.getLogger(DefaultErrorDialog.class);

    private static final int CUSTOM_ELEMENTS_WIDTH_HINT = 300;

    private static final int ERROR_TABLE_HEIGHT_HINT = 180;

    private static final int STACK_TRACE_LINE_COUNT = 15;

    protected static final int SEND_ERROR_REPORT_ID = IDialogConstants.CLIENT_ID + 1;

    private ExceptionHandlerParam exceptHandlerParam;

    /**
     * Dialog title (a localized string).
     */
    private String title;

    /**
     * Collection of all errors currently displayed/displayable.
     */
    private List<ErrorItem> errorList = new ArrayList<ErrorItem>();
    private ErrorTable errorTable;
    private Text stackTraceText;
    private Button detailsButton;

    public DefaultErrorDialog() {
        super(RCPUtil.getActiveShell(), JFaceResources.getString("Problem_Occurred"), //$NON-NLS-1$
                null, JFaceResources.getString("Problem_Occurred"), //$NON-NLS-1$
                ERROR,
                // FIXME: Build problem: IDialogConstants.OK_LABEL is static in RCP but non-static in RAP
                //            new String[] { CompatibleDialogConstants.get().OK_LABEL },
                new String[] { "OK" }, 0);
        setShellStyle(getShellStyle() | SWT.RESIZE);
    }

    @Override
    public void showError(String dialogTitle, String message, ExceptionHandlerParam exceptionHandlerParam) {
        this.title = dialogTitle == null ? JFaceResources.getString("Problem_Occurred") : dialogTitle; //$NON-NLS-1$
        this.exceptHandlerParam = exceptionHandlerParam;

        ErrorItem errorItem = creatErrorItem(dialogTitle, message, exceptHandlerParam.getThrownException(),
                exceptHandlerParam.getTriggerException());
        errorList.add(errorItem);
        if (errorTable != null) {
            errorTable.refresh();
        }
        if (errorList.size() > 1)
            showErrorTable(true);
        setErrorItem(errorItem);
    }

    protected ErrorItem creatErrorItem(String dialogTitle, String message, Throwable thrownException,
            Throwable triggerException) {
        return new ErrorItem(message, thrownException, triggerException);
    }

    @Override
    public int open() {
        ErrorDialogFactory.addDialog(this);
        return super.open();
    }

    @Override
    public boolean close() {
        ErrorDialogFactory.removeDialog(this);
        return super.close();
    }

    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        if (this.title != null)
            shell.setText(this.title);

    }

    @Override
    protected void buttonPressed(int buttonId) {
        switch (buttonId) {
        case IDialogConstants.DETAILS_ID:
            boolean show = ((GridData) stackTraceText.getLayoutData()).heightHint == 0;
            logger.debug("showing stack trace: " + show); //$NON-NLS-1$
            showStackTrace(show);
            break;
        case SEND_ERROR_REPORT_ID:
            //         ErrorItem error = errorTable.getSelectedItem();
            ErrorReport errorReport = null;
            for (ErrorItem error : errorList) {
                if (errorReport == null)
                    errorReport = new ErrorReport(error.getThrownException(), error.getTriggerException());
                else
                    errorReport.addThrowablePair(error.getThrownException(), error.getTriggerException());
            }

            if (errorReport == null) {
                Exception xxx = new IllegalStateException(
                        "There was no error in the errorList!!! How can this happen?!"); //$NON-NLS-1$
                errorReport = new ErrorReport(xxx, xxx);
            }

            if (this.exceptHandlerParam.getErrorScreenShot() != null)
                errorReport.setErrorScreenshot(this.exceptHandlerParam.getErrorScreenShot());

            ErrorReportWizardDialog dlg = new ErrorReportWizardDialog(errorReport);
            okPressed();
            dlg.open();
            break;
        default:
            super.buttonPressed(buttonId);
        }
    }

    protected void setErrorItem(ErrorItem errorItem) {
        String message = errorItem.getMessage();
        String exMsg = errorItem.getThrownException().toString();
        this.message = (message == null || "".equals(message)) ? exMsg : message; //$NON-NLS-1$
        if (messageLabel != null && !messageLabel.isDisposed())
            messageLabel.setText(this.message.replace("&", "&&")); //$NON-NLS-1$ //$NON-NLS-2$
        if (errorTable != null && !errorTable.isDisposed())
            errorTable.setSelectedItem(errorItem);
        if (stackTraceText != null && !stackTraceText.isDisposed())
            stackTraceText.setText(ErrorReport.getExceptionStackTraceAsString(errorItem.getThrownException()));
    }

    boolean errorTableVisible = false;

    private void showErrorTable(boolean newVisible) {
        if (errorTable != null) {
            GridData errorTableGD = ((GridData) errorTable.getLayoutData());
            if (errorTableVisible == newVisible)
                return;
            Point windowSize = getShell().getSize();
            Point oldSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);

            errorTableGD.heightHint = newVisible ? ERROR_TABLE_HEIGHT_HINT : 0;
            errorTable.setVisible(true);

            Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
            getShell().setSize(new Point(windowSize.x, windowSize.y + (newSize.y - oldSize.y)));
        }
        errorTableVisible = newVisible;
    }

    private void showStackTrace(boolean visible) {
        Point windowSize = getShell().getSize();
        Point oldSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
        GridData stackTraceGD = ((GridData) stackTraceText.getLayoutData());
        if (visible) {
            stackTraceGD.heightHint = stackTraceText.getLineHeight() * STACK_TRACE_LINE_COUNT;
            // FIXME: Build-Problem: .SHOW_DETAILS_LABEL is static in RCP but nun-static in RAP, can't build only against one platform!!
            //         detailsButton.setText(CompatibleDialogConstants.get().HIDE_DETAILS_LABEL);
            detailsButton.setText("Hide details");
            stackTraceText.setVisible(true);
        } else {
            stackTraceGD.heightHint = 0;
            // FIXME: Build-Problem: .SHOW_DETAILS_LABEL is static in RCP but nun-static in RAP, can't build only against one platform!!
            //         detailsButton.setText(CompatibleDialogConstants.get().SHOW_DETAILS_LABEL);
            detailsButton.setText("Show details");
            stackTraceText.setVisible(false);
        }
        Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
        getShell().setSize(new Point(windowSize.x, windowSize.y + (newSize.y - oldSize.y)));
    }

    @Override
    protected Control createCustomArea(Composite parent) {
        createErrorTable(parent);
        createStackTraceText(parent);
        return parent;
    }

    private Control createErrorTable(Composite parent) {
        errorTable = new ErrorTable(parent, SWT.NONE);
        errorTable.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent event) {
                errorTable = null;
            }
        });

        applyDialogFont(errorTable);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.widthHint = CUSTOM_ELEMENTS_WIDTH_HINT;
        if (errorTableVisible) {
            gd.heightHint = ERROR_TABLE_HEIGHT_HINT;
            errorTable.setVisible(true);
        } else {
            gd.heightHint = 0;
            errorTable.setVisible(false);
        }
        errorTable.setLayoutData(gd);
        errorTable.setInput(errorList);
        errorTable.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                setErrorItem(errorTable.getSelectedItem());
            }
        });
        return errorTable;
    }

    protected Control createStackTraceText(Composite parent) {
        stackTraceText = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
        applyDialogFont(stackTraceText);
        if (errorTable != null && errorTable.getSelectedItem() != null)
            stackTraceText.setText(
                    ErrorReport.getExceptionStackTraceAsString(errorTable.getSelectedItem().getThrownException()));
        else
            stackTraceText.setText(""); //$NON-NLS-1$
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL
                | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL);
        data.widthHint = CUSTOM_ELEMENTS_WIDTH_HINT;
        data.heightHint = 0; //stackTraceText.getLineHeight() * TEXT_LINE_COUNT;
        stackTraceText.setVisible(false);
        //data.horizontalSpan = 2;
        stackTraceText.setLayoutData(data);
        return stackTraceText;
    }

    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        super.createButtonsForButtonBar(parent);
        createButton(parent, SEND_ERROR_REPORT_ID,
                Messages.getString(
                        "org.nightlabs.base.ui.exceptionhandler.DefaultErrorDialog.button.sendErrorReport.text"), //$NON-NLS-1$
                false);
        // FIXME: Build-Problem: .SHOW_DETAILS_LABEL is static in RCP but nun-static in RAP, can't build only against one platform!!
        //      detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, CompatibleDialogConstants.get().SHOW_DETAILS_LABEL, false);
        detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, "Show details", false);
    }
}