All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pekinsoft.desktop.error.ErrorPane Maven / Gradle / Ivy

/*
 * Copyright (C) 2024 PekinSOFT Systems
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see .
 *
 * *****************************************************************************
 *  Project    :   ErrorPaneInProcess
 *  Class      :   ErrorPane.java
 *  Author     :   Sean Carrick
 *  Created    :   Apr 14, 2024
 *  Modified   :   Apr 14, 2024
 *
 *  Purpose: See class JavaDoc for explanation
 *
 *  Revision History:
 *
 *  WHEN          BY                   REASON
 *  ------------  -------------------  -----------------------------------------
 *  Apr 14, 2024  Sean Carrick         Initial creation.
 * *****************************************************************************
 */
package com.pekinsoft.desktop.error;

import com.pekinsoft.api.*;
import com.pekinsoft.framework.*;
import com.pekinsoft.utils.*;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;

/**
 *
 * @author Sean Carrick <sean at pekinsoft dot com>
 *
 * @version 1.0
 * @since 1.0
 */

public class ErrorPane extends JPanel implements PropertyChangeListener {

    public static final String PROP_ERROR_MESSAGE = "errorMessage";
    public static final String PROP_ERROR_DETAILS = "errorDetails";
    public static final String PROP_ERROR_ICON = "errorIcon";
    public static final String PROP_DETAILS_VISIBLE = "detailsVisible";
    public static final String PROP_IS_FATAL_ERROR = "fatalError";
    
    public static final String SHOW_DETAILS_ACTION_KEY = "doShowDetails";
    public static final String HIDE_DETAILS_ACTION_KEY = "doHideDetails";
    public static final String REPORT_ACTION_KEY = "submitReport";
    public static final String NORMAL_CLOSE_ACTION_KEY = "doClose";
    public static final String FATAL_CLOSE_ACTION_KEY = "doFatalClose";

    public static void showErrorDialog(Throwable cause) {
        showErrorDialog(cause, (ErrorLevel) ErrorLevel.WARNING);
    }

    public static void showErrorDialog(Throwable cause,
            ErrorLevel errorLevel) {
        showErrorDialog(new ErrorInfo(cause, errorLevel));
    }

    public static void showErrorDialog(ErrorInfo info) {
        showErrorDialog(info, null);
    }

    public static void showErrorDialog(ErrorInfo info,
            ErrorReporter reporter) {
        if (info == null) {
            throw new IllegalArgumentException("ErrorInfo cannot be null. The "
                    + "ErrorPane has no support for null ErrorInfo objects.");
        }
        ErrorPane pane = new ErrorPane();
        pane.setErrorInfo(info);
        pane.setErrorReporter(reporter);

        JDialog dlg = new JDialog();
        dlg.setName("ErrorPaneDialog");
        dlg.setTitle(pane.getResourceMap().getString("dialog.title",
                info.getErrorLevel().getName(),
                info.getTitle()));
        pane.setWindow(dlg);
        pane.configureIconLabel();
        pane.constructErrorMessage();
        pane.createDetailsAsHTML();
        dlg.setModal(true);
        dlg.getContentPane().setLayout(new BorderLayout());
        dlg.getContentPane().add(pane, BorderLayout.CENTER);
        dlg.setLocationRelativeTo(null);
        dlg.addWindowListener(new DialogListener(pane));
        dlg.pack();
        WindowManager.getDefault().show(dlg);
    }

    // ------------------------------------------------------------------------
    // BEGIN: ErrorPane Instance Class
    // ------------------------------------------------------------------------

    private ErrorInfo errorInfo = new ErrorInfo("Error",
            "Normally, this place contains the problem description.\n\nYou are "
            + "seeing this text because of one of the following reasons:\n\n"
            + "   * It is a test.\n"
            + "   * The developer has not provided error details.\n"
            + "   * This error message was invoked unexpectedly and "
            + "there are no details available.",
            null, null, null, null, null);
    private ErrorReporter reporter = null;
    private Window window;

    public ErrorPane() {

        initComponents();
    }

    public ErrorInfo getErrorInfo() {
        return errorInfo;
    }

    public void setErrorInfo(ErrorInfo errorInfo) {
        if (errorInfo == null) {
            throw new IllegalArgumentException("ErrorInfo cannot be null. "
                    + "Null ErrorInfo is not supported.");
        }
        ErrorInfo old = getErrorInfo();
        this.errorInfo = errorInfo;

        firePropertyChange("errorInfo", old, getErrorInfo());
        firePropertyChange(PROP_IS_FATAL_ERROR, 
                !(errorInfo.getErrorLevel() == ErrorLevel.FATAL),
                (errorInfo.getErrorLevel() == ErrorLevel.FATAL));
    }

    public boolean isReportAvailable() {
        return getErrorReporter() != null;
    }
    
    public void setReportAvailable(boolean reportAvailable) {
        firePropertyChange("reportAvailable", !isReportAvailable(), isReportAvailable());
    }

    public ErrorReporter getErrorReporter() {
        return reporter;
    }

    public void setErrorReporter(ErrorReporter reporter) {
        boolean old = isReportAvailable();
        this.reporter = reporter;
        boolean now = isReportAvailable();

        firePropertyChange("reportAvailable", old, now);
    }

    public Window getWindow() {
        return window;
    }

    public void setWindow(Window window) {
        this.window = window;
    }

    @AppAction
    public void doShowDetails(ActionEvent evt) {
        detailsPanel.setVisible(true);
        firePropertyChange(PROP_DETAILS_VISIBLE, false, true);
        getWindow().pack();
    }

    @AppAction
    public void doHideDetails(ActionEvent evt) {
        detailsPanel.setVisible(false);
        firePropertyChange(PROP_DETAILS_VISIBLE, true, false);
        getWindow().pack();
    }

    @AppAction
    public void doClose(ActionEvent evt) {
        getWindow().dispose();
    }

    @AppAction
    public void doFatalClose(ActionEvent evt) {
        Application.getInstance().exit(evt, SysExits.EX_SOFTWARE);
    }

    @AppAction(enabledProperty = "reportAvailable")
    public BackgroundTask submitReport(ActionEvent evt) {
        return reporter.reportError();
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        
    }
    protected ResourceMap getResourceMap() {
        return Application.getInstance().getContext().getResourceMap(getClass());
    }

    protected ActionMap myActionMap() {
        return ActionManager.getInstance().getActionMap(getClass(), this);
    }

    private void initComponents() {
        errorMessage = new MessagePanel();
        // Leaving *unnamed* to prevent properties injection.
        addPropertyChangeListener(errorMessage);

        detailsPanel = new DetailsPanel();
        // Leaving *unnamed* to prevent properties injection.
        addPropertyChangeListener(detailsPanel);
        detailsPanel.setVisible(false);

        commandPanel = new CommandPanel(myActionMap());
        // Leaving *unnamed* to prevent properties injection.
        addPropertyChangeListener(commandPanel);
        
        firePropertyChange(PROP_DETAILS_VISIBLE, true, false);
        firePropertyChange(PROP_IS_FATAL_ERROR, 
                !(errorInfo.getErrorLevel() == ErrorLevel.FATAL),
                (errorInfo.getErrorLevel() == ErrorLevel.FATAL));

        setLayout(new BorderLayout());
        add(errorMessage, BorderLayout.NORTH);
        add(detailsPanel, BorderLayout.CENTER);
        add(commandPanel, BorderLayout.SOUTH);
    }

    void configureIconLabel() {
        int errorLevel = errorInfo.getErrorLevel().intValue();
        if (errorLevel == ErrorLevel.FATAL.intValue()) {
            firePropertyChange(PROP_ERROR_ICON, null,
                        getResourceMap().getIcon("ErrorPane.fatalIcon"));
        } else if (errorLevel == ErrorLevel.CRITICAL.intValue()) {
            firePropertyChange(PROP_ERROR_ICON, null,
                        getResourceMap().getIcon("ErrorPane.criticalIcon"));
        } else if (errorLevel == ErrorLevel.ERROR.intValue()) {
            firePropertyChange(PROP_ERROR_ICON, null,
                        getResourceMap().getIcon("ErrorPane.errorIcon"));
        } else {
            firePropertyChange(PROP_ERROR_ICON, null,
                        getResourceMap().getIcon("ErrorPane.warningIcon"));
        }
    }

    void constructErrorMessage() {
        ErrorInfo ei = getErrorInfo();
        StringBuilder sb = new StringBuilder("");

        sb.append("

").append(ei.getTitle()).append("

"); sb.append("
"); sb.append("Exception: "); sb.append("{@code ").append(ei.getErrorException() .getClass().getSimpleName()).append("}"); sb.append("
Message: "); sb.append(StringUtils.escapeXml( ei.getErrorException().getLocalizedMessage())); firePropertyChange(PROP_ERROR_MESSAGE, null, sb.toString()); } void createDetailsAsHTML() { if (errorInfo.getErrorException() != null) { StringBuilder html = new StringBuilder(""); html.append("

").append( StringUtils.escapeXml(errorInfo.getTitle())); html.append("

"); html.append("
"); html.append("
"); html.append("

Details:

"); html.append("

"); html.append(" ").append(StringUtils.escapeXml( errorInfo.getDetailedErrorMessage())); html.append(""); html.append("

ErrorLevel: {@code "); html.append(" ").append(errorInfo.getErrorLevel()); html.append("}"); html.append("

Stacktrace:

"); Throwable ex = errorInfo.getErrorException(); while (ex != null) { html.append("

").append(ex.getLocalizedMessage()); html.append("

"); html.append("
");
                for (StackTraceElement el : ex.getStackTrace()) {
                    html.append("    ").append(StringUtils.escapeXml(
                            el.toString())).append("\n");
                }
                html.append("
"); ex = ex.getCause(); } html.append(""); firePropertyChange(PROP_ERROR_DETAILS, null, html.toString()); } } private MessagePanel errorMessage; private DetailsPanel detailsPanel; private CommandPanel commandPanel; private static class DialogListener extends WindowAdapter { private ErrorPane pane; DialogListener(ErrorPane pane) { this.pane = pane; } @Override public void windowOpened(WindowEvent e) { Window window = e.getWindow(); boolean detailsVisible = window.getSize().height > 320; pane.detailsPanel.setVisible(detailsVisible); pane.commandPanel.detailsVisible(detailsVisible); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy