package jaxe; import java.awt.EventQueue; import java.beans.*; import javax.swing.event.SwingPropertyChangeSupport; import javax.swing.JOptionPane; import textbender.recombinant.common.awt.RunBuffer; import textbender.recombinant.common.beans.PropertyListenerRegistryN; import textbender.recombinant.common.hold.Spool0; import textbender.recombinant.common.lang.*; import textbender.recombinant.common.util.prefs.PreferencesX; /** Common instances. * The single instance of Common itself is available via Common.i(). * * @author Michael Allan <mike@zelea.com> */ public final class Common implements PropertyListenerRegistryN, Thread.UncaughtExceptionHandler, ThrowableHolderModel { /** The single instance of Common. *
* It is not thread safe. Except where marked otherwise, * clients are restricted to the AWT event dispatch thread. *
*/ public static Common i() { return instance; } private Common() { Thread.setDefaultUncaughtExceptionHandler( Common.this ); } // ```````````````````````````````````````````````````````````````````````````````````` // First, so available during initialization below. private final SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport( /*source bean*/Common.this ); // ------------------------------------------------------------------------------------ /** A shared run buffer with a slow queue, invoking runs once per second. */ public RunBuffer slowRunBuffer() { return slowRunBuffer; } private final RunBuffer slowRunBuffer = new RunBuffer ( /*interInvocationMilliseconds*/1000 ); // - P r o p e r t y - L i s t e n e r - R e g i s t r y ------------------------------ public void addPropertyChangeListener( PropertyChangeListener listener ) { assert java.awt.EventQueue.isDispatchThread(); propertyChangeSupport.addPropertyChangeListener( listener ); } public void removePropertyChangeListener( PropertyChangeListener listener ) { assert java.awt.EventQueue.isDispatchThread(); propertyChangeSupport.removePropertyChangeListener( listener ); } // - P r o p e r t y - L i s t e n e r - R e g i s t r y - N -------------------------- public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener ) { assert java.awt.EventQueue.isDispatchThread(); propertyChangeSupport.addPropertyChangeListener( propertyName, listener ); } public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener ) { assert java.awt.EventQueue.isDispatchThread(); propertyChangeSupport.removePropertyChangeListener( propertyName, listener ); } // - T h r o w a b l e - H o l d e r -------------------------------------------------- /** Returns the last throwable shown, per {@linkplain #showThrowable showThrowable}. * The return value is bound to property name throwable. */ public Throwable getThrowable() { return throwable; } private Throwable throwable; private final ThrowableHolderV throwableView; { JOptionPane optionPane = new JOptionPane(); { optionPane.setMessageType( JOptionPane.ERROR_MESSAGE ); final String closeOption = "Close"; optionPane.setOptions( new Object[]{ closeOption }); optionPane.setInitialValue( closeOption ); } throwableView = new ThrowableHolderV( optionPane, Spool0.i() ).init2 // Spool0, never released ( Common.this, /*dialog parent*/null, PreferencesX.userNodeForClass( Common.class ), slowRunBuffer() ); } /** Shows a throwable in a modal dialog. * Use this to display errors or exceptions that occur in response to user actions. * * @throws NullPointerException if the throwable is null * * @see #getThrowable */ public final void showThrowable( Throwable newThrowable ) { assert java.awt.EventQueue.isDispatchThread(); final Throwable oldThrowable = throwable; if( newThrowable.equals( oldThrowable )) return; throwable = newThrowable; propertyChangeSupport.firePropertyChange( "throwable", oldThrowable, newThrowable ); throwableView.dialog().setVisible( true ); } // - U n c a u g h t - E x c e p t i o n - H a n d l e r ------------------------------ /** Handles an otherwise uncaught exception. Thread safe, though other members are not. */ public void uncaughtException( Thread thread, final Throwable throwable ) { if( throwable instanceof ThreadDeath ) throw (ThreadDeath)throwable; // always let it die EventQueue.invokeLater( new Runnable() { public final void run() { showThrowable( throwable ); } // in AWT event dispatch thread }); } ////////////////////////////////////////////////////////////////////////////////////////// // Last, so static fields above initialize, and are available during instantiation below private static final Common instance = new Common(); }