org.jdesktop.swingx.JXErrorPane Maven / Gradle / Ivy
Show all versions of swingx-all Show documentation
/*
* $Id: JXErrorPane.java 4158 2012-02-03 18:29:40Z kschaefe $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* 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
*/
package org.jdesktop.swingx;
import org.jdesktop.beans.JavaBean;
import org.jdesktop.swingx.error.ErrorInfo;
import org.jdesktop.swingx.error.ErrorReporter;
import org.jdesktop.swingx.plaf.ErrorPaneAddon;
import org.jdesktop.swingx.plaf.ErrorPaneUI;
import org.jdesktop.swingx.plaf.LookAndFeelAddons;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* JXErrorPane is a common error component suitable for displaying errors,
* warnings, and exceptional application behavior to users.
*
* User interaction with the JXErrorPane
includes the ability to
* view details associated with the error. This is the primary feature that differentiates
* JXErrorPane
from JOptionPane
. In addition,
* JXErrorPane
specializes in handling unrecoverable errors. If you
* need an error dialog that allows the user to take some action to recover
* from an error (such as "Repair Disk", "Replace All", etc) then you should
* use JOptionPane
.
*
* Data and application state associated with an error are encapsulated
* in the {@link ErrorInfo} class. The
* {@code JXErrorPane} displays the data contained in the {@code ErrorInfo}.
* In addition, {@code ErrorInfo} is passed to the
* {@link ErrorReporter} if the user decides to report
* the incident.
*
* Basic Usage
* Typically, the JXErrorPane
* is not created and displayed directly. Instead, one of the static showXXX methods
* are called that create and display the JXErrorPane
in a
* JDialog
, JFrame
, or JInternalFrame
.
*
* These static showXXX methods all follow the same pattern, namely (
* where XXX could be one of Dialog, Frame, or InternalFrame):
*
* - showXXX(Throwable e): This usage allows you to show a default error
* window, detailing the error
* - showXXX(Component owner, ErrorInfo info): This usage shows an
* error dialog based on the given
ErrorInfo
. The component
* argument is the component over which the dialog should be centered.
* - showXXX(Component owner, JXErrorPane pane): This usage shows
* an error dialog using the given error pane. This allows you to completely
* modify the pane (perhaps installing a custom UI delegate, etc) to present
* to the user
* - createXXX(Component owner, JXErrorPane pane): Creates and returns
* a dialog for presenting the given
JXErrorPane
, but does not
* show it. This allows the developer to modify properties of the dialog
* prior to display
*
*
* Following are some examples and further discussion regarding some of these
* static methods. Example of the most basic usage:
*
* try {
* //do stuff.... something throws an exception in here
* } catch (Exception e) {
* JXErrorPane.showDialog(e);
* }
*
. Alternatively there are showFrame
and
* showInternalFrame
variants of each of the showDialog
* methods described in this API.
*
* While this is the simplest usage, it is not the recommended approach for
* most errors since it yields the most difficult messages for users to understand.
* Instead it is recommended to provide a more useful message for users. For example:
*
* URL url = null;
* try {
* url = new URL(userSuppliedUrl);
* } catch (MalformedURLException e) {
* String msg = "The web resource you entered is not formatted"
* + " correctly.";
* String details = "<html>Web resources should begin with \"http://\""
* + " and cannot contain any spaces. Below are a few"
* + " more guidelines.<ul>"
* + getURLGuidelines()
* + "</ul></html>";
* JXErrorPane.showDialog(myWindow, "Unknown Resource", msg, details, e);
* return false;
* }
*
*
* Before showing the JXErrorPane
in a frame or dialog, you may modify
* the appearance and behavior of the JXErrorPane
by setting one or more of its bean
* properties. For example, to modify the icon shown with a particular
* instance of a JXErrorPane
, you might do the following:
*
* JXErrorPane pane = new JXErrorPane();
* pane.setErrorIcon(myErrorIcon);
* pane.setErrorInfo(new ErrorInfo("Fatal Error", exception));
* JXErrorPane.showDialog(null, pane);
*
*
* JXErrorPane
may also be configured with a "Report" button which allows
* the user to send a bug report, typically through email. This is done through
* the pluggable {@link ErrorReporter} class. Simply instantiate
* some custom subclass of ErrorReporter
and pass the instance into the
* {@link #setErrorReporter} method.
*
* JXErrorPane
can also be used for displaying fatal error messages to
* users. Fatal messages indicate a serious error in the application that cannot
* be corrected and that must result in the termination of the application.
* After the close of a fatal error dialog, the application should
* automatically exit. Fatal messages are identified by the Level
* of the ErrorInfo
being
* {@link org.jdesktop.swingx.error.ErrorLevel}.FATAL
.
*
* By default, when Fatal error dialogs are closed the application exits with
* a code of "1". In other words, System.exit(1)
. If you wish to implement
* custom handling, you can replace the default fatal action in the ActionMap
* of the JXErrorPane
instance. If you specify a custom fatal
* action, then the default action of calling
* System.exit will not occur. You are therefore responsible for shutting down
* the application.
*
* UI Default Keys
* TODO
* JXErrorPane.errorIcon
* or, if not specified, JOptionPane.errorIcon
* JXErrorPane.warningIcon
* or, if not specified, JOptionPane.warningIcon
* JXErrorPane.details_contract_text (ignored on Mac OS X)
* JXErrorPane.details_expand_text (ignored on Mac OS X)
* JXErrorPane.mac.details_contract_text
* JXErrorPane.mac.details_expand_text
* Tree.expandedIcon (on Mac OS X)
* Tree.collapsedIcon (on Mac OS X)
*
* Customizing the Look and Feel
* TODO
*
* @author Richard Bair
* @author Alexander Zuev
* @author Shai Almog
* @author rah003
*/
@JavaBean
public class JXErrorPane extends JComponent {
private static final Logger LOG = Logger.getLogger(JXErrorPane.class.getName());
//---------------------------------------------------- static properties
/**
* Name of the Action used for reporting errors
*/
public static final String REPORT_ACTION_KEY = "report-action";
/**
* Name of the Action used for fatal errors
*/
public static final String FATAL_ACTION_KEY = "fatal-action";
/**
* UI Class ID
*/
public static final String uiClassID = "ErrorPaneUI";
/**
*/
static {
LookAndFeelAddons.contribute(new ErrorPaneAddon());
}
//-------------------------------------------------- instance properties
/**
* ErrorInfo that contains all the information prepared for
* reporting.
*/
private ErrorInfo errorInfo = new ErrorInfo(
"Error",
"Normally this place contains problem description.\n You see this text because one of the following reasons:\n * Either it is a test\n * Developer have not provided error details\n * This error message was invoked unexpectedly and there are no more details available",
null, null, null, null, null
);
/**
* The Icon to use, regardless of the error message. The UI delegate is
* responsible for setting this icon, if the developer has not specified
* the icon.
*/
private Icon icon;
/**
* The delegate to use for reporting errors.
*/
private ErrorReporter reporter;
//--------------------------------------------------------- constructors
/**
* Create a new JXErrorPane
.
*/
public JXErrorPane() {
updateUI();
}
//------------------------------------------------------------- UI Logic
/**
* Returns the look and feel (L&F) object that renders this component.
*
* @return the {@link ErrorPaneUI} object that renders this component
*/
public ErrorPaneUI getUI() {
return (ErrorPaneUI) ui;
}
/**
* Sets the look and feel (L&F) object that renders this component.
*
* @param ui the ErrorPaneUI L&F object
* @see javax.swing.UIDefaults#getUI
*/
public void setUI(ErrorPaneUI ui) {
super.setUI(ui);
}
/**
* Returns the name of the L&F class that renders this component.
*
* @return the string {@link #uiClassID}
* @see JComponent#getUIClassID
* @see javax.swing.UIDefaults#getUI
*/
@Override
public String getUIClassID() {
return uiClassID;
}
/**
* Notification from the UIManager
that the L&F has changed.
* Replaces the current UI object with the latest version from the
* UIManager
.
*
* @see JComponent#updateUI
*/
@Override
public void updateUI() {
setUI((ErrorPaneUI) LookAndFeelAddons.getUI(this, ErrorPaneUI.class));
}
//-------------------------------------------- public methods/properties
/**
* Sets the ErrorInfo for this dialog. ErrorInfo can't be null.
*
* @param info ErrorInfo that incorporates all the details about the error. Null value is not supported.
*/
public void setErrorInfo(ErrorInfo info) {
if (info == null) {
throw new NullPointerException("ErrorInfo can't be null. Provide valid ErrorInfo object.");
}
ErrorInfo old = this.errorInfo;
this.errorInfo = info;
firePropertyChange("errorInfo", old, this.errorInfo);
}
/**
* Gets the JXErrorPane
's ErrorInfo
*
* @return ErrorInfo
assigned to this dialog
*/
public ErrorInfo getErrorInfo() {
return errorInfo;
}
/**
* Specifies the icon to use
*
* @param icon the Icon to use. May be null.
*/
public void setIcon(Icon icon) {
Icon old = this.icon;
this.icon = icon;
firePropertyChange("icon", old, this.icon);
}
/**
* Returns the Icon used
*
* @return the Icon
*/
public Icon getIcon() {
return icon;
}
/**
* Sets the {@link ErrorReporter} delegate to use. This delegate is called
* automatically when the report action is fired.
*
* @param reporter the ErrorReporter to use. If null, the report button will
* not be shown in the error dialog.
*/
public void setErrorReporter(ErrorReporter reporter) {
ErrorReporter old = getErrorReporter();
this.reporter = reporter;
firePropertyChange("errorReporter", old, getErrorReporter());
}
/**
* Gets the {@link ErrorReporter} delegate in use.
*
* @return the ErrorReporter. May be null.
*/
public ErrorReporter getErrorReporter() {
return reporter;
}
//------------------------------------------------------- static methods
/**
* Constructs and shows the error dialog for the given exception. The
* exceptions message will be the errorMessage, and the stacktrace will form
* the details for the error dialog.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the dialog shown will be modal. Otherwise, this thread will
* block until the error dialog has been shown and hidden on the EDT.
*
* @param e Exception that contains information about the error cause and stack trace
*/
public static void showDialog(Throwable e) {
ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
showDialog(null, ii);
}
/**
* Constructs and shows the error dialog, using the given
* ErrorInfo
to initialize the view.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the dialog shown will be modal. Otherwise, this thread will
* block until the error dialog has been shown and hidden on the EDT.
*
* @param owner Owner of this error dialog. Determines the Window in which the dialog
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param info ErrorInfo
that incorporates all the information about the error
*/
public static void showDialog(Component owner, ErrorInfo info) {
JXErrorPane pane = new JXErrorPane();
pane.setErrorInfo(info);
showDialog(owner, pane);
}
/**
* Constructs and shows the error dialog, using the given
* JXErrorPane
for the view portion of the dialog.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the dialog shown will be modal. Otherwise, this thread will
* block until the error dialog has been shown and hidden on the EDT.
*
* @param owner Owner of this error dialog. Determines the Window in which the dialog
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the dialog.
*/
public static void showDialog(Component owner, JXErrorPane pane) {
Runnable r = () -> {
JDialog dlg = createDialog(owner, pane);
dlg.setVisible(true);
};
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InvocationTargetException | InterruptedException ex) {
LOG.log(Level.WARNING, ex.getMessage(), ex);
}
} else {
r.run();
}
}
/**
* Constructs and returns an error dialog, using the given
* JXErrorPane
for the view portion of the dialog.
*
* This method may be called from any thread. It does not block. The
* caller is responsible for ensuring that the dialog is shown and manipulated
* on the AWT event dispatch thread. A common way to do this is to use
* SwingUtilities.invokeAndWait
or
* SwingUtilities.invokeLater()
.
*
* @param owner Owner of this error dialog. Determines the Window in which the dialog
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the dialog.
* @return a JDialog
configured to display the error.
*/
public static JDialog createDialog(Component owner, JXErrorPane pane) {
JDialog window = pane.getUI().getErrorDialog(owner);
// If the owner is null applies orientation of the shared
// hidden window used as owner.
if (owner != null) {
pane.applyComponentOrientation(owner.getComponentOrientation());
} else {
pane.applyComponentOrientation(window.getComponentOrientation());
}
window.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
window.pack();
window.setLocationRelativeTo(owner);
return window;
}
/**
* Constructs and shows the error frame for the given exception. The
* exceptions message will be the errorMessage, and the stacktrace will form
* the details for the error dialog.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param e Exception that contains information about the error cause and stack trace
*/
public static void showFrame(Throwable e) {
ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
showFrame(null, ii);
}
/**
* Constructs and shows the error frame, using the given
* ErrorInfo
to initialize the view.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param owner Owner of this error frame. Determines the Window in which the frame
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param info ErrorInfo
that incorporates all the information about the error
*/
public static void showFrame(Component owner, ErrorInfo info) {
JXErrorPane pane = new JXErrorPane();
pane.setErrorInfo(info);
showFrame(owner, pane);
}
/**
* Constructs and shows the error frame, using the given
* JXErrorPane
for the view portion of the frame.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param owner Owner of this error frame. Determines the Window in which the dialog
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the frame.
*/
public static void showFrame(Component owner, JXErrorPane pane) {
Runnable r = () -> {
JFrame window = createFrame(owner, pane);
window.setVisible(true);
};
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InvocationTargetException | InterruptedException ex) {
LOG.log(Level.WARNING, ex.getMessage(), ex);
}
} else {
r.run();
}
}
/**
* Constructs and returns an error frame, using the given
* JXErrorPane
for the view portion of the frame.
*
* This method may be called from any thread. It does not block. The
* caller is responsible for ensuring that the frame is shown and manipulated
* on the AWT event dispatch thread. A common way to do this is to use
* SwingUtilities.invokeAndWait
or
* SwingUtilities.invokeLater()
.
*
* @param owner Owner of this error frame. Determines the Window in which the frame
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the frame.
* @return a JFrame
configured to display the error.
*/
public static JFrame createFrame(Component owner, JXErrorPane pane) {
JFrame window = pane.getUI().getErrorFrame(owner);
// If the owner is null applies orientation of the shared
// hidden window used as owner.
if (owner != null) {
pane.applyComponentOrientation(owner.getComponentOrientation());
} else {
pane.applyComponentOrientation(window.getComponentOrientation());
}
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.pack();
return window;
}
/**
* Constructs and shows the error frame for the given exception. The
* exceptions message will be the errorMessage, and the stacktrace will form
* the details for the error dialog.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param e Exception that contains information about the error cause and stack trace
*/
public static void showInternalFrame(Throwable e) {
ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
showInternalFrame(null, ii);
}
/**
* Constructs and shows the error frame, using the given
* ErrorInfo
to initialize the view.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param owner Owner of this error frame. Determines the Window in which the frame
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param info ErrorInfo
that incorporates all the information about the error
*/
public static void showInternalFrame(Component owner, ErrorInfo info) {
JXErrorPane pane = new JXErrorPane();
pane.setErrorInfo(info);
showInternalFrame(owner, pane);
}
/**
* Constructs and shows the error frame, using the given
* JXErrorPane
for the view portion of the frame.
*
* This method may be called from any thread. It will actually show the error
* dialog on the AWT event dispatch thread. This method blocks. If called
* on the EDT, the frame shown will be modal. Otherwise, this thread will
* block until the error frame has been shown and hidden on the EDT.
*
* @param owner Owner of this error frame. Determines the Window in which the dialog
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the frame.
*/
public static void showInternalFrame(Component owner, JXErrorPane pane) {
Runnable r = () -> {
JInternalFrame window = createInternalFrame(owner, pane);
window.setVisible(true);
};
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InvocationTargetException | InterruptedException ex) {
LOG.log(Level.WARNING, ex.getMessage(), ex);
}
} else {
r.run();
}
}
/**
* Constructs and returns an error frame, using the given
* JXErrorPane
for the view portion of the frame.
*
* This method may be called from any thread. It does not block. The
* caller is responsible for ensuring that the frame is shown and manipulated
* on the AWT event dispatch thread. A common way to do this is to use
* SwingUtilities.invokeAndWait
or
* SwingUtilities.invokeLater()
.
*
* @param owner Owner of this error frame. Determines the Window in which the frame
* is displayed; if the owner
has
* no Window
, a default Frame
is used
* @param pane JXErrorPane
which will form the content area
* of the frame.
* @return a JInternalFrame
configured to display the error.
*/
public static JInternalFrame createInternalFrame(Component owner, JXErrorPane pane) {
JInternalFrame window = pane.getUI().getErrorInternalFrame(owner);
// If the owner is null applies orientation of the shared
// hidden window used as owner.
if (owner != null) {
pane.applyComponentOrientation(owner.getComponentOrientation());
} else {
pane.applyComponentOrientation(window.getComponentOrientation());
}
window.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
window.pack();
//TODO!
// window.setLocationRelativeTo(owner);
return window;
}
}