
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