001/*
002 * $Id: JXErrorPane.java 4158 2012-02-03 18:29:40Z kschaefe $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 */
021package org.jdesktop.swingx;
022
023import java.awt.Component;
024import java.lang.reflect.InvocationTargetException;
025
026import javax.swing.Icon;
027import javax.swing.JComponent;
028import javax.swing.JDialog;
029import javax.swing.JFrame;
030import javax.swing.JInternalFrame;
031import javax.swing.SwingUtilities;
032
033import org.jdesktop.beans.JavaBean;
034import org.jdesktop.swingx.error.ErrorInfo;
035import org.jdesktop.swingx.error.ErrorReporter;
036import org.jdesktop.swingx.plaf.ErrorPaneAddon;
037import org.jdesktop.swingx.plaf.ErrorPaneUI;
038import org.jdesktop.swingx.plaf.LookAndFeelAddons;
039
040/**
041 * <p>JXErrorPane is a common error component suitable for displaying errors,
042 * warnings, and exceptional application behavior to users.</p>
043 * 
044 * <p>User interaction with the <code>JXErrorPane</code> includes the ability to
045 * view details associated with the error. This is the primary feature that differentiates
046 * <code>JXErrorPane</code> from <code>JOptionPane</code>. In addition,
047 * <code>JXErrorPane</code> specializes in handling unrecoverable errors. If you
048 * need an error dialog that allows the user to take some action to recover
049 * from an error (such as "Repair Disk", "Replace All", etc) then you should
050 * use <code>JOptionPane</code>.</p>
051 * 
052 * <p>Data and application state associated with an error are encapsulated
053 * in the {@link org.jdesktop.swingx.error.ErrorInfo} class. The
054 * {@code JXErrorPane} displays the data contained in the {@code ErrorInfo}.
055 * In addition, {@code ErrorInfo} is passed to the
056 * {@link org.jdesktop.swingx.error.ErrorReporter} if the user decides to report
057 * the incident.</p>
058 * 
059 * <h2>Basic Usage</h2>
060 * <p>Typically, the <code>JXErrorPane</code>
061 * is not created and displayed directly. Instead, one of the static showXXX methods
062 * are called that create and display the <code>JXErrorPane</code> in a 
063 * <code>JDialog</code>, <code>JFrame</code>, or <code>JInternalFrame</code>.</p>
064 * 
065 * <p>These static showXXX methods all follow the same pattern, namely (
066 * where XXX could be one of Dialog, Frame, or InternalFrame):
067 * <ul>
068 *  <li><b>showXXX(Throwable e)</b>: This usage allows you to show a default error
069 *      window, detailing the error</li>
070 *  <li><b>showXXX(Component owner, ErrorInfo info)</b>: This usage shows an
071 *      error dialog based on the given <code>ErrorInfo</code>. The component
072 *      argument is the component over which the dialog should be centered.</li>
073 *  <li><b>showXXX(Component owner, JXErrorPane pane)</b>: This usage shows
074 *      an error dialog using the given error pane. This allows you to completely
075 *      modify the pane (perhaps installing a custom UI delegate, etc) to present
076 *      to the user</li>
077 *  <li><b>createXXX(Component owner, JXErrorPane pane)</b>: Creates and returns
078 *      a dialog for presenting the given <code>JXErrorPane</code>, but does not
079 *      show it. This allows the developer to modify properties of the dialog
080 *      prior to display</li>
081 * </ul></p>
082 * 
083 * <p>Following are some examples and further discussion regarding some of these
084 * static methods. Example of the most basic usage:
085 * <pre><code>
086 *      try {
087 *          //do stuff.... something throws an exception in here
088 *      } catch (Exception e) {
089 *          JXErrorPane.showDialog(e);
090 *      }
091 * </code></pre>. Alternatively there are <code>showFrame</code> and
092 * <code>showInternalFrame</code> variants of each of the <code>showDialog</code>
093 * methods described in this API.</p>
094 *
095 * <p>While this is the simplest usage, it is not the recommended approach for
096 * most errors since it yields the most difficult messages for users to understand.
097 * Instead it is recommended to provide a more useful message for users. For example:
098 * <pre><code>
099 *      URL url = null;
100 *      try {
101 *          url = new URL(userSuppliedUrl);
102 *      } catch (MalformedURLException e) {
103 *          String msg = "The web resource you entered is not formatted"
104 *                      + " correctly.";
105 *          String details = "&lt;html&gt;Web resources should begin with \"http://\""
106 *                      + " and cannot contain any spaces. Below are a few"
107 *                      + " more guidelines.&lt;ul&gt;"
108 *                      + getURLGuidelines()
109 *                      + "&lt;/ul&gt;&lt;/html&gt;";
110 *          JXErrorPane.showDialog(myWindow, "Unknown Resource", msg, details, e);
111 *          return false;
112 *      }
113 * </code></pre></p>
114 * 
115 * <p>Before showing the <code>JXErrorPane</code> in a frame or dialog, you may modify
116 * the appearance and behavior of the <code>JXErrorPane</code> by setting one or more of its bean
117 * properties. For example, to modify the icon shown with a particular
118 * instance of a <code>JXErrorPane</code>, you might do the following:
119 * <pre><code>
120 *      JXErrorPane pane = new JXErrorPane();
121 *      pane.setErrorIcon(myErrorIcon);
122 *      pane.setErrorInfo(new ErrorInfo("Fatal Error", exception));
123 *      JXErrorPane.showDialog(null, pane);
124 * </code></pre></p>
125 *
126 * <p><code>JXErrorPane</code> may also be configured with a "Report" button which allows
127 * the user to send a bug report, typically through email. This is done through
128 * the pluggable {@link org.jdesktop.swingx.error.ErrorReporter} class. Simply instantiate
129 * some custom subclass of <code>ErrorReporter</code> and pass the instance into the
130 * {@link #setErrorReporter} method.</p>
131 *
132 * <p><code>JXErrorPane</code> can also be used for displaying fatal error messages to
133 * users. Fatal messages indicate a serious error in the application that cannot
134 * be corrected and that must result in the termination of the application. 
135 * After the close of a fatal error dialog, the application should
136 * automatically exit. Fatal messages are identified by the <code>Level</code>
137 * of the <code>ErrorInfo</code> being 
138 * {@link org.jdesktop.swingx.error.ErrorLevel}<code>.FATAL</code>.</p>
139 * 
140 * <p>By default, when Fatal error dialogs are closed the application exits with
141 * a code of "1". In other words, <code>System.exit(1)</code>. If you wish to implement
142 * custom handling, you can replace the default fatal action in the <code>ActionMap</code>
143 * of the <code>JXErrorPane</code> instance. If you specify a custom fatal 
144 * action, then the default action of calling
145 * System.exit will not occur. You are therefore responsible for shutting down
146 * the application.</p>
147 * 
148 * <h2>UI Default Keys</h2>
149 * <p>TODO</p>
150 * JXErrorPane.errorIcon
151 *      or, if not specified, JOptionPane.errorIcon
152 * JXErrorPane.warningIcon
153 *      or, if not specified, JOptionPane.warningIcon
154 * JXErrorPane.details_contract_text (ignored on Mac OS X)
155 * JXErrorPane.details_expand_text (ignored on Mac OS X)
156 * JXErrorPane.mac.details_contract_text
157 * JXErrorPane.mac.details_expand_text
158 * Tree.expandedIcon (on Mac OS X)
159 * Tree.collapsedIcon (on Mac OS X)
160 * 
161 * <h2>Customizing the Look and Feel</h2>
162 * <p>TODO</p>
163 * 
164 *
165 * @status REVIEWED
166 *
167 * @author Richard Bair
168 * @author Alexander Zuev
169 * @author Shai Almog
170 * @author rah003
171 */
172@JavaBean
173public class JXErrorPane extends JComponent {
174    //---------------------------------------------------- static properties
175    /**
176     * Name of the Action used for reporting errors
177     */
178    public static final String REPORT_ACTION_KEY = "report-action";
179    /**
180     * Name of the Action used for fatal errors
181     */
182    public static final String FATAL_ACTION_KEY = "fatal-action";
183    /**
184     * UI Class ID
185     */
186    public final static String uiClassID = "ErrorPaneUI";
187    
188    /**
189     */
190    static {
191        LookAndFeelAddons.contribute(new ErrorPaneAddon());
192    }
193    
194    //-------------------------------------------------- instance properties
195    
196    /**
197     * ErrorInfo that contains all the information prepared for
198     * reporting.
199     */
200    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);
201    /**
202     * The Icon to use, regardless of the error message. The UI delegate is
203     * responsible for setting this icon, if the developer has not specified
204     * the icon.
205     */
206    private Icon icon;
207    /**
208     * The delegate to use for reporting errors.
209     */
210    private ErrorReporter reporter;
211    
212    //--------------------------------------------------------- constructors
213
214    /**
215     * Create a new <code>JXErrorPane</code>.
216     */
217    public JXErrorPane() {
218        super();
219        updateUI();
220    }
221    
222    //------------------------------------------------------------- UI Logic
223    
224    /**
225     * Returns the look and feel (L&F) object that renders this component.
226     *
227     * @return the {@link ErrorPaneUI} object that renders this component
228     */
229    public ErrorPaneUI getUI() {
230        return (ErrorPaneUI)ui;
231    }
232
233    /**
234     * Sets the look and feel (L&F) object that renders this component.
235     * 
236     * @param ui
237     *            the ErrorPaneUI L&F object
238     * @see javax.swing.UIDefaults#getUI
239     * @beaninfo bound: true hidden: true attribute: visualUpdate true
240     *           description: The UI object that implements the Component's
241     *           LookAndFeel.
242     */
243    public void setUI(ErrorPaneUI ui) {
244        super.setUI(ui);
245    }
246
247    /**
248     * Returns the name of the L&F class that renders this component.
249     *
250     * @return the string {@link #uiClassID}
251     * @see javax.swing.JComponent#getUIClassID
252     * @see javax.swing.UIDefaults#getUI
253     */
254    @Override
255    public String getUIClassID() {
256        return uiClassID;
257    }
258
259    /**
260     * Notification from the <code>UIManager</code> that the L&F has changed.
261     * Replaces the current UI object with the latest version from the
262     * <code>UIManager</code>.
263     * 
264     * @see javax.swing.JComponent#updateUI
265     */
266    @Override
267    public void updateUI() {
268        setUI((ErrorPaneUI) LookAndFeelAddons
269                .getUI(this, ErrorPaneUI.class));
270    }
271    
272    //-------------------------------------------- public methods/properties
273    
274    /**
275     * Sets the ErrorInfo for this dialog. ErrorInfo can't be null.
276     *
277     * @param info ErrorInfo that incorporates all the details about the error. Null value is not supported.
278     */
279    public void setErrorInfo(ErrorInfo info) {
280        if (info == null) {
281            throw new NullPointerException("ErrorInfo can't be null. Provide valid ErrorInfo object.");
282        }
283        ErrorInfo old = this.errorInfo;
284        this.errorInfo = info;
285        firePropertyChange("errorInfo", old, this.errorInfo);
286    }
287    
288    /**
289     * Gets the <code>JXErrorPane</code>'s <code>ErrorInfo</code>
290     *
291     * @return <code>ErrorInfo</code> assigned to this dialog
292     */
293    public ErrorInfo getErrorInfo() {
294        return errorInfo;
295    }
296    
297    /**
298     * Specifies the icon to use
299     *
300     * @param icon the Icon to use. May be null.
301     */
302    public void setIcon(Icon icon) {
303        Icon old = this.icon;
304        this.icon = icon;
305        firePropertyChange("icon", old, this.icon);
306    }
307    
308    /**
309     * Returns the Icon used
310     *
311     * @return the Icon
312     */
313    public Icon getIcon() {
314        return icon;
315    }
316    
317    /**
318     * Sets the {@link ErrorReporter} delegate to use. This delegate is called
319     * automatically when the report action is fired.
320     * 
321     * @param reporter the ErrorReporter to use. If null, the report button will
322     *        not be shown in the error dialog.
323     */
324    public void setErrorReporter(ErrorReporter reporter) {
325        ErrorReporter old = getErrorReporter();
326        this.reporter = reporter;
327        firePropertyChange("errorReporter", old, getErrorReporter());
328    }
329    
330    /**
331     * Gets the {@link ErrorReporter} delegate in use.
332     * 
333     * @return the ErrorReporter. May be null.
334     */
335    public ErrorReporter getErrorReporter() {
336        return reporter;
337    }
338    
339    //------------------------------------------------------- static methods
340    
341    /**
342     * <p>Constructs and shows the error dialog for the given exception.  The 
343     * exceptions message will be the errorMessage, and the stacktrace will form 
344     * the details for the error dialog.</p>
345     * 
346     * <p>This method may be called from any thread. It will actually show the error
347     * dialog on the AWT event dispatch thread. This method blocks. If called
348     * on the EDT, the dialog shown will be modal. Otherwise, this thread will
349     * block until the error dialog has been shown and hidden on the EDT.</p>
350     * 
351     * @param e Exception that contains information about the error cause and stack trace
352     */
353    public static void showDialog(Throwable e) {
354        ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
355        showDialog(null, ii);
356    }
357    
358    /**
359     * <p>Constructs and shows the error dialog, using the given
360     * <code>ErrorInfo</code> to initialize the view.</p>
361     * 
362     * <p>This method may be called from any thread. It will actually show the error
363     * dialog on the AWT event dispatch thread. This method blocks. If called
364     * on the EDT, the dialog shown will be modal. Otherwise, this thread will
365     * block until the error dialog has been shown and hidden on the EDT.</p>
366     * 
367     * @param owner Owner of this error dialog. Determines the Window in which the dialog
368     *        is displayed; if the <code>owner</code> has
369     *        no <code>Window</code>, a default <code>Frame</code> is used
370     * @param info <code>ErrorInfo</code> that incorporates all the information about the error
371     */
372    public static void showDialog(Component owner, ErrorInfo info) {
373        JXErrorPane pane = new JXErrorPane();
374        pane.setErrorInfo(info);
375        showDialog(owner, pane);
376    }
377    
378    /**
379     * <p>Constructs and shows the error dialog, using the given
380     * <code>JXErrorPane</code> for the view portion of the dialog.</p>
381     * 
382     * <p>This method may be called from any thread. It will actually show the error
383     * dialog on the AWT event dispatch thread. This method blocks. If called
384     * on the EDT, the dialog shown will be modal. Otherwise, this thread will
385     * block until the error dialog has been shown and hidden on the EDT.</p>
386     * 
387     * @param owner Owner of this error dialog. Determines the Window in which the dialog
388     *        is displayed; if the <code>owner</code> has
389     *        no <code>Window</code>, a default <code>Frame</code> is used
390     * @param pane <code>JXErrorPane</code> which will form the content area
391     *        of the dialog.
392     */
393    public static void showDialog(final Component owner, final JXErrorPane pane) {
394        Runnable r = new Runnable() {
395            @Override
396            public void run() {
397                JDialog dlg = createDialog(owner, pane);
398                dlg.setVisible(true);
399            }
400        };
401        
402        if (!SwingUtilities.isEventDispatchThread()) {
403            try {
404                SwingUtilities.invokeAndWait(r);
405            } catch (InvocationTargetException ex) {
406                ex.printStackTrace();
407            } catch (InterruptedException ex) {
408                ex.printStackTrace();
409            }
410        } else {
411            r.run();
412        }
413    }
414    
415    /**
416     * <p>Constructs and returns an error dialog, using the given
417     * <code>JXErrorPane</code> for the view portion of the dialog.</p>
418     * 
419     * <p>This method may be called from any thread. It does not block. The
420     * caller is responsible for ensuring that the dialog is shown and manipulated
421     * on the AWT event dispatch thread. A common way to do this is to use
422     * <code>SwingUtilities.invokeAndWait</code> or 
423     * <code>SwingUtilities.invokeLater()</code>.</p>
424     * 
425     * @param owner Owner of this error dialog. Determines the Window in which the dialog
426     *        is displayed; if the <code>owner</code> has
427     *        no <code>Window</code>, a default <code>Frame</code> is used
428     * @param pane <code>JXErrorPane</code> which will form the content area
429     *        of the dialog.
430     * @return a <code>JDialog</code> configured to display the error.
431     */
432    public static JDialog createDialog(Component owner, JXErrorPane pane) {
433        JDialog window = pane.getUI().getErrorDialog(owner);
434        // If the owner is null applies orientation of the shared
435        // hidden window used as owner.
436        if(owner != null) {
437            pane.applyComponentOrientation(owner.getComponentOrientation());
438        } else {
439            pane.applyComponentOrientation(window.getComponentOrientation());
440        }
441        window.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
442        window.pack();
443        window.setLocationRelativeTo(owner);
444        return window;
445    }
446    
447    /**
448     * <p>Constructs and shows the error frame for the given exception.  The 
449     * exceptions message will be the errorMessage, and the stacktrace will form 
450     * the details for the error dialog.</p>
451     * 
452     * <p>This method may be called from any thread. It will actually show the error
453     * dialog on the AWT event dispatch thread. This method blocks. If called
454     * on the EDT, the frame shown will be modal. Otherwise, this thread will
455     * block until the error frame has been shown and hidden on the EDT.</p>
456     * 
457     * @param e Exception that contains information about the error cause and stack trace
458     */
459    public static void showFrame(Throwable e) {
460        ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
461        showFrame(null, ii);
462    }
463    
464    /**
465     * <p>Constructs and shows the error frame, using the given
466     * <code>ErrorInfo</code> to initialize the view.</p>
467     * 
468     * <p>This method may be called from any thread. It will actually show the error
469     * dialog on the AWT event dispatch thread. This method blocks. If called
470     * on the EDT, the frame shown will be modal. Otherwise, this thread will
471     * block until the error frame has been shown and hidden on the EDT.</p>
472     * 
473     * @param owner Owner of this error frame. Determines the Window in which the frame
474     *        is displayed; if the <code>owner</code> has
475     *        no <code>Window</code>, a default <code>Frame</code> is used
476     * @param info <code>ErrorInfo</code> that incorporates all the information about the error
477     */
478    public static void showFrame(Component owner, ErrorInfo info) {
479        JXErrorPane pane = new JXErrorPane();
480        pane.setErrorInfo(info);
481        showFrame(owner, pane);
482    }
483    
484    /**
485     * <p>Constructs and shows the error frame, using the given
486     * <code>JXErrorPane</code> for the view portion of the frame.</p>
487     * 
488     * <p>This method may be called from any thread. It will actually show the error
489     * dialog on the AWT event dispatch thread. This method blocks. If called
490     * on the EDT, the frame shown will be modal. Otherwise, this thread will
491     * block until the error frame has been shown and hidden on the EDT.</p>
492     * 
493     * @param owner Owner of this error frame. Determines the Window in which the dialog
494     *        is displayed; if the <code>owner</code> has
495     *        no <code>Window</code>, a default <code>Frame</code> is used
496     * @param pane <code>JXErrorPane</code> which will form the content area
497     *        of the frame.
498     */
499    public static void showFrame(final Component owner, final JXErrorPane pane) {
500        Runnable r = new Runnable() {
501            @Override
502            public void run() {
503                JFrame window = createFrame(owner, pane);
504                window.setVisible(true);
505            }
506        };
507        
508        if (!SwingUtilities.isEventDispatchThread()) {
509            try {
510                SwingUtilities.invokeAndWait(r);
511            } catch (InvocationTargetException ex) {
512                ex.printStackTrace();
513            } catch (InterruptedException ex) {
514                ex.printStackTrace();
515            }
516        } else {
517            r.run();
518        }
519    }
520    
521    /**
522     * <p>Constructs and returns an error frame, using the given
523     * <code>JXErrorPane</code> for the view portion of the frame.</p>
524     * 
525     * <p>This method may be called from any thread. It does not block. The
526     * caller is responsible for ensuring that the frame is shown and manipulated
527     * on the AWT event dispatch thread. A common way to do this is to use
528     * <code>SwingUtilities.invokeAndWait</code> or 
529     * <code>SwingUtilities.invokeLater()</code>.</p>
530     * 
531     * @param owner Owner of this error frame. Determines the Window in which the frame
532     *        is displayed; if the <code>owner</code> has
533     *        no <code>Window</code>, a default <code>Frame</code> is used
534     * @param pane <code>JXErrorPane</code> which will form the content area
535     *        of the frame.
536     * @return a <code>JFrame</code> configured to display the error.
537     */
538    public static JFrame createFrame(Component owner, JXErrorPane pane) {
539        JFrame window = pane.getUI().getErrorFrame(owner);
540        // If the owner is null applies orientation of the shared
541        // hidden window used as owner.
542        if(owner != null) {
543            pane.applyComponentOrientation(owner.getComponentOrientation());
544        } else {
545            pane.applyComponentOrientation(window.getComponentOrientation());
546        }
547        window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
548        window.pack();
549//        window.setLocationRelativeTo(owner);
550        return window;
551    }
552    
553    /**
554     * <p>Constructs and shows the error frame for the given exception.  The 
555     * exceptions message will be the errorMessage, and the stacktrace will form 
556     * the details for the error dialog.</p>
557     * 
558     * <p>This method may be called from any thread. It will actually show the error
559     * dialog on the AWT event dispatch thread. This method blocks. If called
560     * on the EDT, the frame shown will be modal. Otherwise, this thread will
561     * block until the error frame has been shown and hidden on the EDT.</p>
562     * 
563     * @param e Exception that contains information about the error cause and stack trace
564     */
565    public static void showInternalFrame(Throwable e) {
566        ErrorInfo ii = new ErrorInfo(null, null, null, null, e, null, null);
567        showInternalFrame(null, ii);
568    }
569    
570    /**
571     * <p>Constructs and shows the error frame, using the given
572     * <code>ErrorInfo</code> to initialize the view.</p>
573     * 
574     * <p>This method may be called from any thread. It will actually show the error
575     * dialog on the AWT event dispatch thread. This method blocks. If called
576     * on the EDT, the frame shown will be modal. Otherwise, this thread will
577     * block until the error frame has been shown and hidden on the EDT.</p>
578     * 
579     * @param owner Owner of this error frame. Determines the Window in which the frame
580     *        is displayed; if the <code>owner</code> has
581     *        no <code>Window</code>, a default <code>Frame</code> is used
582     * @param info <code>ErrorInfo</code> that incorporates all the information about the error
583     */
584    public static void showInternalFrame(Component owner, ErrorInfo info) {
585        JXErrorPane pane = new JXErrorPane();
586        pane.setErrorInfo(info);
587        showInternalFrame(owner, pane);
588    }
589    
590    /**
591     * <p>Constructs and shows the error frame, using the given
592     * <code>JXErrorPane</code> for the view portion of the frame.</p>
593     * 
594     * <p>This method may be called from any thread. It will actually show the error
595     * dialog on the AWT event dispatch thread. This method blocks. If called
596     * on the EDT, the frame shown will be modal. Otherwise, this thread will
597     * block until the error frame has been shown and hidden on the EDT.</p>
598     * 
599     * @param owner Owner of this error frame. Determines the Window in which the dialog
600     *        is displayed; if the <code>owner</code> has
601     *        no <code>Window</code>, a default <code>Frame</code> is used
602     * @param pane <code>JXErrorPane</code> which will form the content area
603     *        of the frame.
604     */
605    public static void showInternalFrame(final Component owner, final JXErrorPane pane) {
606        Runnable r = new Runnable() {
607            @Override
608            public void run() {
609                JInternalFrame window = createInternalFrame(owner, pane);
610                window.setVisible(true);                
611            }
612        };
613        
614        if (!SwingUtilities.isEventDispatchThread()) {
615            try {
616                SwingUtilities.invokeAndWait(r);
617            } catch (InvocationTargetException ex) {
618                ex.printStackTrace();
619            } catch (InterruptedException ex) {
620                ex.printStackTrace();
621            }
622        } else {
623            r.run();
624        }
625    }
626    
627    /**
628     * <p>Constructs and returns an error frame, using the given
629     * <code>JXErrorPane</code> for the view portion of the frame.</p>
630     * 
631     * <p>This method may be called from any thread. It does not block. The
632     * caller is responsible for ensuring that the frame is shown and manipulated
633     * on the AWT event dispatch thread. A common way to do this is to use
634     * <code>SwingUtilities.invokeAndWait</code> or 
635     * <code>SwingUtilities.invokeLater()</code>.</p>
636     * 
637     * @param owner Owner of this error frame. Determines the Window in which the frame
638     *    is displayed; if the <code>owner</code> has
639     *    no <code>Window</code>, a default <code>Frame</code> is used
640     * @param pane <code>JXErrorPane</code> which will form the content area
641     *    of the frame.
642     * @return a <code>JInternalFrame</code> configured to display the error.
643     */
644    public static JInternalFrame createInternalFrame(Component owner, JXErrorPane pane) {
645        JInternalFrame window = pane.getUI().getErrorInternalFrame(owner);
646        // If the owner is null applies orientation of the shared
647        // hidden window used as owner.
648        if(owner != null) {
649            pane.applyComponentOrientation(owner.getComponentOrientation());
650        } else {
651            pane.applyComponentOrientation(window.getComponentOrientation());
652        }
653        window.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
654        window.pack();
655        //TODO!
656//                window.setLocationRelativeTo(owner);
657        return window;
658    }
659    
660}