VStar.java

/**
 * VStar: a statistical analysis tool for variable star data.
 * Copyright (C) 2009  AAVSO (http://www.aavso.org/)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
package org.aavso.tools.vstar.ui;

import java.io.File;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import javax.swing.UIManager;

import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.scripting.ScriptRunner;
import org.aavso.tools.vstar.ui.dialog.MessageBox;
import org.aavso.tools.vstar.ui.dialog.plugin.manager.PluginManager;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.resources.PluginLoader;
import org.aavso.tools.vstar.ui.vela.VeLaDialog;
import org.aavso.tools.vstar.util.locale.LocaleProps;
import org.aavso.tools.vstar.util.property.ApplicationProperties;

/**
 * The VStar GUI.
 */
public class VStar {

    public static final String LOG_DIR = System.getProperty("user.home") + File.separator + "vstar_log";

    public static final String LOG_PATH = LOG_DIR + File.separator + "vstar.log";

    public static Logger LOGGER;

    static {
        try {
            File logDir = new File(LOG_DIR);
            if (!logDir.isDirectory()) {
                logDir.mkdir();
            }
            Handler fh = new FileHandler(LOG_PATH);
            fh.setFormatter(new SimpleFormatter());
            LOGGER = Logger.getLogger("VStar Logger");
            LOGGER.setUseParentHandlers(false);
            LOGGER.addHandler(fh);

        } catch (Exception e) {
            // Default to console?
        }
    }

    private static boolean setNativeLookAndFeel = true;

    private static boolean loadPlugins = true;

    private static boolean runScript = false;

    private static String scriptPath = null;

    private static boolean openVeLaDialog = false;

    public static void main(String[] args) {

        String os_name = "";
        // For Mac OS X, make it look more native by using the screen
        // menu bar. Suggested by Adam Weber.
        try {
            os_name = System.getProperty("os.name");
            if (os_name.startsWith("Mac OS X")) {
                System.setProperty("apple.laf.useScreenMenuBar", "true");
                System.setProperty("com.apple.mrj.application.apple.menu.about.name", "VStar");
            }
        } catch (Exception e) {
            System.err.println("Unable to detect operating system. Exiting.");
            System.exit(1);
        }

        processCmdLineArgs(args);

        if (setNativeLookAndFeel) {
            // Set the Look & Feel of the application to be native.
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                // Under Windows, the default TextArea font is too small.
                // Making TextArea the same as TextField fixes this.
                // We should make this fix AFTER setting native Look & Feel!
                if (os_name.startsWith("Windows")) {
                    // [https://stackoverflow.com/questions/6461506/jtextarea-default-font-very-small-in-windows]
                    UIManager.getDefaults().put("TextArea.font", UIManager.getFont("TextField.font"));
                }
            } catch (Exception e) {
                System.err.println("Unable to set native look & feel. Exiting.");
                System.exit(1);
            }
        }

        // Classes SeriesType and LocaleProps have static prefs members of Preferences
        // type; those members cannot be created from within plug-ins in WebStart mode due to
        // security restrictions.
        //
        // As far as 'prefs' in both classes are created with a 'static' block of code,
        // any reference to the class
        // initializes 'prefs'. This is ensured by a call of the empty initClass()
        // method.
        //
        // After initialization, 'prefs' can be accessed from within plug-ins.
        SeriesType.initClass();
        LocaleProps.initClass();

        // If there's no command-line option that says we shouldn't load
        // plug-ins and the plug-in manager says it's okay to load them, then go
        // ahead.
        if (loadPlugins && PluginManager.shouldLoadPlugins()) {
            // Load plug-ins, if any exist and plug-in loading is enabled.
            PluginLoader.loadPlugins();
        }

        // Create an uncaught exception handler.
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread th, Throwable ex) {
                // LOGGER.log(Level.SEVERE, "Uncaught Exception", ex);
                MessageBox.showErrorDialog("Error", ex);
            }
        });

        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });

        if (openVeLaDialog) {
            showVeLaDialog();
        }
    }

    /**
     * Create and display the main window.
     */
    private static void createAndShowGUI() {
        try {
            MainFrame frame = new MainFrame();
            final ApplicationProperties appProps = new ApplicationProperties(frame);

            frame.setSize(appProps.getMainWdwWidth(), appProps.getMainWdwHeight());
            frame.setLocation(appProps.getMainWdwUpperLeftX(), appProps.getMainWdwUpperLeftY());

            // We need all the underlying main frame apparatus, but we may just want the
            // VeLa dialog.
            frame.setVisible(!openVeLaDialog);

            // We create a shutdown task rather than a window listener
            // to store application properties, otherwise on the Mac, we
            // would also have to trap the VStar (vs File) menu Quit item.
            // This shutdown task should work uniformly across operating
            // systems. The frame stored within appProps cannot be GC'd
            // until appProps is, so its state will still be valid at the
            // time run() is invoked.
            Runnable shutdownTask = new Runnable() {
                public void run() {
                    appProps.update();
                }
            };

            Runtime.getRuntime().addShutdownHook(new Thread(shutdownTask, "Application shutdown task"));

            if (scriptPath != null) {
                new ScriptRunner(false).runScript(new File(scriptPath));
            }
        } catch (Throwable t) {
            MessageBox.showErrorDialog(Mediator.getUI().getComponent(), "Error", t.getLocalizedMessage());
        }
    }

    /**
     * Open the VeLa dialog.
     */
    private static void showVeLaDialog() {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new VeLaDialog();
                System.exit(0);
            }
        });
    }

    /**
     * Process the command-line arguments. Note: If we do anything more complex than
     * this, consideration should be given to using a library such as:
     * http://commons.apache.org/cli/
     * 
     * @param args The command-line arguments; may be empty.
     */
    private static void processCmdLineArgs(String[] args) {
        for (String arg : args) {
            if ("--help".equals(arg)) {
                System.out.println(
                        "usage: vstar [--default-look-and-feel] [--noplugins] [--script path] [--VeLa-dialog]");
                System.exit(0);
            } else if ("--default-look-and-feel".equals(arg)) {
                setNativeLookAndFeel = false;
            } else if ("--noplugins".equals(arg)) {
                loadPlugins = false;
            } else if ("--script".equals(arg)) {
                runScript = true;
            } else if (runScript) {
                scriptPath = arg;
            } else if ("--VeLa-dialog".equalsIgnoreCase(arg)) {
                openVeLaDialog = true;
            }
        }
    }
}