package hirondelle.stocks.preferences;

import java.util.logging.*;
import javax.swing.JOptionPane;
import java.awt.EventQueue;
import hirondelle.stocks.util.Consts;

* An implementation of a Java Logging API {@link Handler}
* which displays a short message to the user using a <tt>JOptionPane</tt>, and 
* is intended only for <tt>Level.SEVERE</tt> messages.
* <P>The issue arises of how to inform the user in the case of a 
* <tt>Level.SEVERE</tt> message : if all 
* <tt>Handler</tt>s are purely textual, then in a graphical application it is 
* not uncommon for the user to be unaware of the problem, since the textual output  
* is not necessarily visible. This <tt>Handler</tt> addresses the issue by defining 
* a graphical logging <tt>Handler</tt>, which will always get the user's attention 
* by using a visual pop-up message.
* <P>This <tt>Handler</tt> is unusual for two reasons :
* <ul>
* <li> it is intended only for <tt>SEVERE</tt> messages, so 
* that the user is never overloaded with too many pop-up messages.
* <li>it is intended only for programmatic use, and should not appear in the 
* <tt></tt> config file. 
* <P>The content of the message is taken from 
* {@link LogRecord#getMessage}, which is usually a short piece 
* of text. The intent is that this <tt>Handler</tt> present only the barest
* facts, and that the user refer to other text-based <tt>Handler</tt> tools 
* for further information.
* <P>This <tt>Handler</tt> can be used both from the event dispatch thread, 
* and from any other thread. Thus, it may be used by any worker thread which 
* is experiencing difficulties.
* <P>Typically, this <tt>Handler</tt> is attached to the root <tt>Logger</tt>,
* and is thus inherited by all all other <tt>Logger</tt>s.
public final class OptionPaneExceptionHandler extends Handler {

  * Implementation Note :
  * A simple way to test the behavior of this class is 
  * to attempt a File->Import with corrupted data.
  * Construct this <tt>Handler</tt> with default settings.
  * These defaults should not be changed :
  * <li><tt>Level</tt> is set to <tt>SEVERE</tt>
  * <li>{@link Formatter} is set to a {@link SimpleFormatter}
  public OptionPaneExceptionHandler(){
    setFormatter( new SimpleFormatter() );

  /** No-operation. */
  @Override public void close() { }
  /** No-operation.  */
  @Override public void flush() { }

  * If <tt>aLogRecord</tt> satisfies {@link Handler#isLoggable},
  * then a short message is displayed to the user using a <tt>JOptionPane</tt>.
  * <P>The message is presented in a modal dialog, and will grab the focus. 
  * <P> Warning : if a <tt>SEVERE</tt> message is generated during startup, before 
  * the main window is displayed, then any pop-up message generated by this class will 
  * eventually be hidden behind the main window.
  @Override public void publish(LogRecord aLogRecord) {
    if ( ! isLoggable(aLogRecord) ) return;
    if (EventQueue.isDispatchThread()) {
    else {
      //using a SwingWorker would be a more modern style, but this still works fine too
      EventQueue.invokeLater( new Worker(aLogRecord) );

  * Add a <tt>OptionPaneExceptionHandler</tt> to the root <tt>Logger</tt>.
  *<P>Typically, the <tt>Handler</tt> attached to the root <tt>Logger</tt> is 
  * inherited by all other <tt>Logger</tt>s.
  * <P>Called both upon startup and when refreshing the 
  * <tt></tt> file. In the case of startup, it is best to 
  * call this method only after the main window is shown ; otherwise, it is likely that
  * any startup error messages generated by this class will be hidden
  * by the main window.
  public static void attachToRootLogger(){
    Handler handler =  new OptionPaneExceptionHandler();
    Logger rootLogger = Logger.getLogger(Consts.EMPTY_STRING);
  private static final String TITLE = "Error Occured";
  private void showGui(LogRecord aLogRecord){
    String message = getFormatter().formatMessage(aLogRecord);
    JOptionPane.showMessageDialog(null, message, TITLE, JOptionPane.ERROR_MESSAGE);
  private class Worker implements Runnable {
    Worker(LogRecord aLogRecord){
      fLogRecord = aLogRecord;
    @Override public void run(){
    private LogRecord fLogRecord;