edu.ku.brc.specify.ui.AppBase.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.specify.ui.AppBase.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.specify.ui;

import static edu.ku.brc.ui.UIHelper.createLabel;
import static edu.ku.brc.ui.UIRegistry.getLocalizedMessage;
import static edu.ku.brc.ui.UIRegistry.getResourceString;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Vector;
import java.util.prefs.BackingStoreException;

import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.install4j.api.launcher.ApplicationLauncher;
import com.install4j.api.update.ApplicationDisplayMode;
import com.install4j.api.update.UpdateChecker;
import com.install4j.api.update.UpdateDescriptor;
import com.install4j.api.update.UpdateDescriptorEntry;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import edu.ku.brc.af.auth.SecurityMgr;
import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.FrameworkAppIFace;
import edu.ku.brc.af.core.GenericGUIDGeneratorFactory;
import edu.ku.brc.af.core.MacOSAppHandler;
import edu.ku.brc.af.core.RecordSetFactory;
import edu.ku.brc.af.core.SchemaI18NService;
import edu.ku.brc.af.core.db.BackupServiceFactory;
import edu.ku.brc.af.core.db.DBTableIdMgr;
import edu.ku.brc.af.core.expresssearch.QueryAdjusterForDomain;
import edu.ku.brc.af.prefs.AppPreferences;
import edu.ku.brc.af.prefs.AppPrefsEditor;
import edu.ku.brc.af.prefs.PreferencesDlg;
import edu.ku.brc.af.tasks.BaseTask;
import edu.ku.brc.af.ui.ProcessListUtil;
import edu.ku.brc.af.ui.db.DatabaseLoginListener;
import edu.ku.brc.af.ui.db.DatabaseLoginPanel;
import edu.ku.brc.af.ui.forms.FormHelper;
import edu.ku.brc.af.ui.forms.ViewFactory;
import edu.ku.brc.af.ui.forms.formatters.DataObjFieldFormatMgr;
import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterMgr;
import edu.ku.brc.af.ui.weblink.WebLinkMgr;
import edu.ku.brc.dbsupport.CustomQueryFactory;
import edu.ku.brc.dbsupport.DBConnection;
import edu.ku.brc.dbsupport.DBMSUserMgr;
import edu.ku.brc.dbsupport.DataProviderFactory;
import edu.ku.brc.dbsupport.SchemaUpdateService;
import edu.ku.brc.exceptions.ExceptionTracker;
import edu.ku.brc.helpers.SwingWorker;
import edu.ku.brc.specify.config.init.RegisterSpecify;
import edu.ku.brc.specify.conversion.BasicSQLUtils;
import edu.ku.brc.specify.datamodel.Collection;
import edu.ku.brc.specify.datamodel.Discipline;
import edu.ku.brc.specify.datamodel.Division;
import edu.ku.brc.specify.datamodel.Institution;
import edu.ku.brc.specify.datamodel.SpecifyUser;
import edu.ku.brc.ui.CommandAction;
import edu.ku.brc.ui.CommandDispatcher;
import edu.ku.brc.ui.CommandListener;
import edu.ku.brc.ui.CustomDialog;
import edu.ku.brc.ui.CustomFrame;
import edu.ku.brc.ui.GraphicsUtils;
import edu.ku.brc.ui.IconManager;
import edu.ku.brc.ui.JStatusBar;
import edu.ku.brc.ui.JTiledToolbar;
import edu.ku.brc.ui.RolloverCommand;
import edu.ku.brc.ui.ToolbarLayoutManager;
import edu.ku.brc.ui.UIHelper;
import edu.ku.brc.ui.UIRegistry;
import edu.ku.brc.ui.VerticalSeparator;
import edu.ku.brc.ui.dnd.GhostGlassPane;
import edu.ku.brc.ui.skin.SkinItem;
import edu.ku.brc.ui.skin.SkinsMgr;
import edu.ku.brc.util.AttachmentUtils;
import edu.ku.brc.util.TeeOutputStream;

/**
 * A base class for Specify derived Applications
 *
 * @author rods
 *
 * @code_status Alpha
 *
 * Sep 2, 2009
 *
 */
@SuppressWarnings("serial") //$NON-NLS-1$
public class AppBase extends JPanel implements DatabaseLoginListener, CommandListener, FrameworkAppIFace {
    private static final Logger log = Logger.getLogger(AppBase.class);

    private static AppBase appInstance = null; // needed for ActionListeners etc.

    public static final String ERROR_LOG = "error.log";
    public static final String SPECIFY_LOG = "specify.log";
    public static final String OUTPUT_LOG = "output.log";
    public static final String ERRORSYS_LOG = "error_sys.log";

    // Status Bar
    protected JStatusBar statusField = null;
    protected JMenuBar menuBar = null;
    protected JFrame topFrame = null;
    protected JLabel appIcon = null;

    protected DatabaseLoginPanel dbLoginPanel = null;
    protected String databaseName = null;
    protected String userName = null;

    protected GhostGlassPane glassPane;

    protected String appName = "Specify"; //$NON-NLS-1$
    protected String appVersion = "6.0"; //$NON-NLS-1$

    protected String appBuildVersion = "(Unknown)"; //$NON-NLS-1$

    /**
     * Constructor.
     */
    public AppBase() {

    }

    /**
     * The very very first step in initializing Specify. 
     */
    protected void preStartUp() {
        //UIHelper.attachUnhandledException();

        // we simply need to create this class, not use it
        new MacOSAppHandler(this);

        // Name factories
        setUpSystemProperties();
    }

    /**
     * Check for and kills and existing embedded MySQl processes.
     */
    public static void checkForSpecifyAppsRunning() {
        List<Integer> ids = ProcessListUtil.getProcessIdWithText("exe4j.moduleName", "specify", "SpiReport");
        if (ids.size() > 1) {
            UIRegistry.showLocalizedMsg("WARNING", "Specify.TOO_MANY_SP");
            System.exit(0);
        }
    }

    /**
     * Setup all the System properties. This names all the needed factories. 
     */
    public static void setUpSystemProperties() {
        // Name factories
        System.setProperty(ViewFactory.factoryName, "edu.ku.brc.specify.config.SpecifyViewFactory"); // Needed by ViewFactory //$NON-NLS-1$
        System.setProperty(AppContextMgr.factoryName, "edu.ku.brc.specify.config.SpecifyAppContextMgr"); // Needed by AppContextMgr //$NON-NLS-1$
        System.setProperty(AppPreferences.factoryName, "edu.ku.brc.specify.config.AppPrefsDBIOIImpl"); // Needed by AppReferences //$NON-NLS-1$
        System.setProperty("edu.ku.brc.ui.ViewBasedDialogFactoryIFace", "edu.ku.brc.specify.ui.DBObjDialogFactory"); // Needed By UIRegistry //$NON-NLS-1$ //$NON-NLS-2$
        System.setProperty("edu.ku.brc.ui.forms.DraggableRecordIdentifierFactory", //$NON-NLS-1$
                "edu.ku.brc.specify.ui.SpecifyDraggableRecordIdentiferFactory"); // Needed By the Form System  //$NON-NLS-1$
        System.setProperty("edu.ku.brc.dbsupport.AuditInterceptor", //$NON-NLS-1$
                "edu.ku.brc.specify.dbsupport.AuditInterceptor"); // Needed By the Form System for updating Lucene and logging transactions  //$NON-NLS-1$
        System.setProperty(DataProviderFactory.factoryName, "edu.ku.brc.specify.dbsupport.HibernateDataProvider"); // Needed By the Form System and any Data Get/Set //$NON-NLS-1$ //$NON-NLS-2$
        System.setProperty("edu.ku.brc.ui.db.PickListDBAdapterFactory", //$NON-NLS-1$
                "edu.ku.brc.specify.ui.db.PickListDBAdapterFactory"); // Needed By the Auto Cosmplete UI  //$NON-NLS-1$
        System.setProperty(CustomQueryFactory.factoryName,
                "edu.ku.brc.specify.dbsupport.SpecifyCustomQueryFactory"); //$NON-NLS-1$
        System.setProperty(UIFieldFormatterMgr.factoryName, "edu.ku.brc.specify.ui.SpecifyUIFieldFormatterMgr"); // Needed for CatalogNumberign //$NON-NLS-1$
        System.setProperty(QueryAdjusterForDomain.factoryName,
                "edu.ku.brc.specify.dbsupport.SpecifyQueryAdjusterForDomain"); // Needed for ExpressSearch //$NON-NLS-1$
        System.setProperty(SchemaI18NService.factoryName, "edu.ku.brc.specify.config.SpecifySchemaI18NService"); // Needed for Localization and Schema //$NON-NLS-1$
        System.setProperty(WebLinkMgr.factoryName, "edu.ku.brc.specify.config.SpecifyWebLinkMgr"); // Needed for WebLnkButton //$NON-NLS-1$
        System.setProperty(DataObjFieldFormatMgr.factoryName,
                "edu.ku.brc.specify.config.SpecifyDataObjFieldFormatMgr"); // Needed for WebLnkButton //$NON-NLS-1$
        System.setProperty(RecordSetFactory.factoryName, "edu.ku.brc.specify.config.SpecifyRecordSetFactory"); // Needed for Searching //$NON-NLS-1$
        System.setProperty(DBTableIdMgr.factoryName, "edu.ku.brc.specify.config.SpecifyDBTableIdMgr"); // Needed for Tree Field Names //$NON-NLS-1$
        System.setProperty(SecurityMgr.factoryName, "edu.ku.brc.af.auth.specify.SpecifySecurityMgr"); // Needed for Tree Field Names //$NON-NLS-1$
        //System.setProperty(UserAndMasterPasswordMgr.factoryName,               "edu.ku.brc.af.auth.specify.SpecifySecurityMgr");              // Needed for Tree Field Names //$NON-NLS-1$
        System.setProperty(BackupServiceFactory.factoryName, "edu.ku.brc.af.core.db.MySQLBackupService"); // Needed for Backup and Restore //$NON-NLS-1$
        System.setProperty(ExceptionTracker.factoryName, "edu.ku.brc.specify.config.SpecifyExceptionTracker"); // Needed for Backup and Restore //$NON-NLS-1$

        System.setProperty(DBMSUserMgr.factoryName, "edu.ku.brc.dbsupport.MySQLDMBSUserMgr");
        System.setProperty(SchemaUpdateService.factoryName,
                "edu.ku.brc.specify.dbsupport.SpecifySchemaUpdateService"); // needed for updating the schema
        System.setProperty(GenericGUIDGeneratorFactory.factoryName,
                "edu.ku.brc.specify.config.SpecifyGUIDGeneratorFactory");
    }

    /**
     * @param imgEncoded uuencoded image string
     */
    protected void setAppIcon(final String imgEncoded) {
        String appIconName = "AppIcon";
        String innerAppIconName = "InnerAppIcon";

        ImageIcon appImgIcon = null;
        if (StringUtils.isNotEmpty(imgEncoded)) {
            appImgIcon = GraphicsUtils.uudecodeImage("", imgEncoded); //$NON-NLS-1$
            if (appImgIcon != null && appImgIcon.getIconWidth() == 32 && appImgIcon.getIconHeight() == 32) {
                appIcon.setIcon(appImgIcon);
                CustomDialog.setAppIcon(appImgIcon);
                CustomFrame.setAppIcon(appImgIcon);
                IconManager.register(innerAppIconName, appImgIcon, null, IconManager.IconSize.Std32);
                return;
            }
        }
        appImgIcon = IconManager.getImage(appIconName, IconManager.IconSize.Std32); //$NON-NLS-1$
        appIcon.setIcon(appImgIcon);
        if (!UIHelper.isMacOS()) {
            appImgIcon = IconManager.getImage("SpecifyWhite32", IconManager.IconSize.Std32); //$NON-NLS-1$
        }
        CustomDialog.setAppIcon(appImgIcon);
        CustomFrame.setAppIcon(appImgIcon);
        IconManager.register(innerAppIconName, appImgIcon, null, IconManager.IconSize.Std32);

        if (this.topFrame != null) {
            this.topFrame.setIconImage(appImgIcon.getImage());
        }
    }

    /**
     *
     * @return the toolbar for the app
     */
    protected JToolBar createToolBar() {

        JToolBar toolBar;
        SkinItem skinItem = SkinsMgr.getSkinItem("ToolBar");
        if (SkinsMgr.hasSkins() && skinItem != null
                && (skinItem.getBGImage() != null || skinItem.getBgColor() != null)) {
            JTiledToolbar ttb = new JTiledToolbar(skinItem.getBGImage());
            if (skinItem.getBgColor() != null) {
                ttb.setBackground(skinItem.getBgColor());
                ttb.setOpaque(true);
            } else {
                ttb.setOpaque(false);
            }
            toolBar = ttb;
        } else {
            toolBar = new JToolBar();
        }
        toolBar.setLayout(new ToolbarLayoutManager(2, 2));

        appIcon = new JLabel("  "); //$NON-NLS-1$

        setAppIcon(AppPreferences.getRemote().get("ui.formatting.user_icon_image", null)); //$NON-NLS-1$

        CommandDispatcher.register("Preferences", new CommandListener() { //$NON-NLS-1$
            public void doCommand(CommandAction cmdAction) {
                if (cmdAction.isAction("Updated")) //$NON-NLS-1$
                {
                    setAppIcon(AppPreferences.getRemote().get("ui.formatting.user_icon_image", null)); //$NON-NLS-1$
                }
            }
        });

        return toolBar;
    }

    /**
     * Show preferences.
     */
    public void doPreferences() {
        //AppContextMgr acm        = AppContextMgr.getInstance();
        if (AppContextMgr.getInstance().hasContext()) {
            PreferencesDlg dlg = new PreferencesDlg(false);
            dlg.setVisible(true);
        } else {
            UIRegistry.showLocalizedMsg("Specify.NOTAVAIL");
        }
    }

    /**
     * 
     */
    protected void checkForUpdates() {
        try {
            UpdateDescriptor updateDesc = UpdateChecker.getUpdateDescriptor(
                    UIRegistry.getResourceString("UPDATE_PATH"), ApplicationDisplayMode.UNATTENDED);

            UpdateDescriptorEntry entry = updateDesc.getPossibleUpdateEntry();

            if (entry != null) {
                Object[] options = { getResourceString("Specify.INSTALLUPDATE"), //$NON-NLS-1$
                        getResourceString("Specify.SKIP") //$NON-NLS-1$
                };
                int userChoice = JOptionPane.showOptionDialog(UIRegistry.getTopWindow(),
                        getLocalizedMessage("Specify.UPDATE_AVAIL", entry.getNewVersion()), //$NON-NLS-1$
                        getResourceString("Specify.UPDATE_AVAIL_TITLE"), //$NON-NLS-1$
                        JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
                if (userChoice == JOptionPane.YES_OPTION) {
                    if (!doExit(false)) {
                        return;
                    }

                } else {
                    return;
                }
            } else {
                UIRegistry.showLocalizedError("Specify.NO_UPDATE_AVAIL");
                return;
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            UIRegistry.showLocalizedError("Specify.UPDATE_CHK_ERROR");
            return;
        }

        try {
            ApplicationLauncher.Callback callback = new ApplicationLauncher.Callback() {
                public void exited(int exitValue) {
                    System.err.println("exitValue: " + exitValue);
                    //startApp(doConfig);
                }

                public void prepareShutdown() {
                    System.err.println("prepareShutdown");

                }
            };
            ApplicationLauncher.launchApplication("100", null, true, callback);

        } catch (Exception ex) {
            System.err.println("EXPCEPTION");
        }
    }

    /**
     * @param path
     * @param fileName
     * @param doCreate
     * @return
     */
    private static File getFile(final String path, final String fileName, final boolean doCreate) {
        String fullPath = path + File.separator + fileName;
        File file = new File(fullPath);
        if (file.exists()) {
            return file;
        }

        if (doCreate) {
            File dir = new File(path);
            if (dir.exists() || dir.mkdirs()) {
                return file;
            }
        }
        return null;
    }

    /**
     * @param fileName
     * @return
     */
    private static File getFullLogFilePath(final String fileName) {
        String homePath = System.getProperty("user.home");
        String userHome = homePath + File.separator + "Specify";

        File logFile = getFile(userHome, fileName, true);
        if (logFile != null)
            return logFile;

        return null;
    }

    /**
     * Creates a ScrollPane with the text from the log file.
     * @param logFile the file
     * @param doError indicates it should display the error log
     * @return the ScrollPane.
     */
    protected static JScrollPane getLogFilePanel(final File logFile, final boolean doError) {
        JTextArea textArea = new JTextArea();
        if (logFile.exists()) {
            try {
                textArea.setText(FileUtils.readFileToString(logFile));

            } catch (Exception ex) {
            } // no catch on purpose

        } else {
            textArea.setText(
                    doError ? getResourceString("Specify.LOG_NO_ERRORS") : getResourceString("Specify.LOG_EMPTY")); //$NON-NLS-1$ //$NON-NLS-2$
        }
        textArea.setEditable(false);

        return new JScrollPane(textArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    }

    /**
     * Creates a modal dialog displaying the the error and specify log files. 
     */
    public static void displaySpecifyLogFiles() {
        File spLogFile = getFullLogFilePath(AppBase.SPECIFY_LOG); //$NON-NLS-1$
        File errLogFile = getFullLogFilePath(AppBase.ERRORSYS_LOG); //$NON-NLS-1$

        JTabbedPane tabPane = new JTabbedPane();
        tabPane.add(getResourceString("Specify.ERROR"), getLogFilePanel(errLogFile, true)); //$NON-NLS-1$
        tabPane.add("Specify", getLogFilePanel(spLogFile, true)); //$NON-NLS-1$

        String title = getResourceString("Specify.LOG_FILES_TITLE");//$NON-NLS-1$
        CustomDialog dialog = new CustomDialog((JFrame) UIRegistry.getTopWindow(), title, true, CustomDialog.OK_BTN,
                tabPane);
        String okLabel = getResourceString("Specify.CLOSE");//$NON-NLS-1$
        dialog.setOkLabel(okLabel);
        dialog.createUI();
        dialog.setSize(800, 600);
        UIHelper.centerWindow(dialog);
        dialog.setVisible(true);
    }

    /**
     * Sets up StdErr and StdOut to be 'tee'd' to files. 
     */
    public static void setupTeeForStdErrStdOut(final boolean doStdErr, final boolean doStdOut) {
        try {
            if (doStdOut) {
                // Tee standard output
                File file = getFullLogFilePath(OUTPUT_LOG);
                if (file != null) {
                    PrintStream out = new PrintStream(new FileOutputStream(file));
                    PrintStream tee = new TeeOutputStream(System.out, out);
                    System.setOut(tee);
                }
            }

            if (doStdErr) {
                // Tee standard error
                File file = getFullLogFilePath(ERRORSYS_LOG);
                if (file != null) {
                    PrintStream err = new PrintStream(new FileOutputStream(file));
                    PrintStream tee = new TeeOutputStream(System.err, err);
                    System.setErr(tee);
                }
            }

        } catch (FileNotFoundException e) {
        }
    }

    /**
     * 
     */
    private void openPrefsEditor(final AppPreferences prefs, final String titleKey) {
        String titleStr = UIRegistry.getResourceString("Specify." + titleKey); //$NON-NLS-1$
        final CustomDialog dialog = new CustomDialog(topFrame, titleStr, true, CustomDialog.OK_BTN,
                new AppPrefsEditor(prefs));
        String okLabel = UIRegistry.getResourceString("Specify.CLOSE"); //$NON-NLS-1$
        dialog.setOkLabel(okLabel);
        dialog.pack();
        UIHelper.centerAndShow(dialog);
        if (!dialog.isCancelled()) {
            try {
                prefs.flush();
            } catch (BackingStoreException ex) {
            }

            CommandDispatcher.dispatch(new CommandAction("Preferences", "Changed", prefs));
        }
    }

    /**
     * 
     */
    private void openLocalPrefs() {
        openPrefsEditor(AppPreferences.getLocalPrefs(), "LOCAL_PREFS");
    }

    /**
     * 
     */
    private void openRemotePrefs() {
        openPrefsEditor(AppPreferences.getRemote(), "REMOTE_PREFS");
    }

    /**
     * 
     */
    private void openGlobalPrefs() {
        openPrefsEditor(AppPreferences.getGlobalPrefs(), "GLOBAL_PREFS");
    }

    /**
     * Shows the About dialog.
     */
    public void doAbout() {
        AppContextMgr acm = AppContextMgr.getInstance();
        boolean hasContext = acm.hasContext();

        int baseNumRows = 9;
        String serverName = AppPreferences.getLocalPrefs().get("login.servers_selected", null);
        if (serverName != null) {
            baseNumRows++;
        }

        CellConstraints cc = new CellConstraints();
        PanelBuilder infoPB = new PanelBuilder(new FormLayout("p,6px,f:p:g",
                "p,4px,p,4px," + UIHelper.createDuplicateJGoodiesDef("p", "2px", baseNumRows)));

        JLabel iconLabel = new JLabel(IconManager.getIcon("SpecifyLargeIcon"), SwingConstants.CENTER); //$NON-NLS-1$
        PanelBuilder iconPB = new PanelBuilder(new FormLayout("p", "20px,t:p,f:p:g"));
        iconPB.add(iconLabel, cc.xy(1, 2));

        if (hasContext) {
            DBTableIdMgr tableMgr = DBTableIdMgr.getInstance();
            boolean hasReged = !RegisterSpecify.isAnonymous() && RegisterSpecify.hasInstitutionRegistered();

            int y = 1;
            infoPB.addSeparator(getResourceString("Specify.SYS_INFO"), cc.xyw(1, y, 3));
            y += 2;

            JLabel lbl = UIHelper.createLabel(databaseName);
            infoPB.add(UIHelper.createI18NFormLabel("Specify.DB"), cc.xy(1, y));
            infoPB.add(lbl, cc.xy(3, y));
            y += 2;
            lbl.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        openLocalPrefs();
                    }
                }
            });

            infoPB.add(UIHelper.createFormLabel(tableMgr.getTitleForId(Institution.getClassTableId())),
                    cc.xy(1, y));
            infoPB.add(lbl = UIHelper.createLabel(acm.getClassObject(Institution.class).getName()), cc.xy(3, y));
            y += 2;
            lbl.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        openRemotePrefs();
                    }
                }
            });
            infoPB.add(UIHelper.createFormLabel(tableMgr.getTitleForId(Division.getClassTableId())), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(acm.getClassObject(Division.class).getName()), cc.xy(3, y));
            y += 2;

            infoPB.add(UIHelper.createFormLabel(tableMgr.getTitleForId(Discipline.getClassTableId())), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(acm.getClassObject(Discipline.class).getName()), cc.xy(3, y));
            y += 2;

            infoPB.add(UIHelper.createFormLabel(tableMgr.getTitleForId(Collection.getClassTableId())), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(acm.getClassObject(Collection.class).getCollectionName()), cc.xy(3, y));
            y += 2;

            infoPB.add(UIHelper.createI18NFormLabel("Specify.BLD"), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(appBuildVersion), cc.xy(3, y));
            y += 2;

            infoPB.add(UIHelper.createI18NFormLabel("Specify.REG"), cc.xy(1, y));
            infoPB.add(UIHelper.createI18NLabel(hasReged ? "Specify.HASREG" : "Specify.NOTREG"), cc.xy(3, y));
            y += 2;

            String isaNumber = RegisterSpecify.getISANumber();
            infoPB.add(UIHelper.createI18NFormLabel("Specify.ISANUM"), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(StringUtils.isNotEmpty(isaNumber) ? isaNumber : ""), cc.xy(3, y));
            y += 2;

            if (serverName != null) {
                infoPB.add(UIHelper.createI18NFormLabel("Specify.SERVER"), cc.xy(1, y));
                infoPB.add(UIHelper.createLabel(StringUtils.isNotEmpty(serverName) ? serverName : ""), cc.xy(3, y));
                y += 2;
            }

            if (StringUtils.contains(DBConnection.getInstance().getConnectionStr(), "mysql")) {
                Vector<Object[]> list = BasicSQLUtils.query("select version() as ve");
                if (list != null && list.size() > 0) {
                    infoPB.add(UIHelper.createFormLabel("MySQL Version"), cc.xy(1, y));
                    infoPB.add(UIHelper.createLabel(list.get(0)[0].toString()), cc.xy(3, y));
                    y += 2;
                }
            }

            infoPB.add(UIHelper.createFormLabel("Java Version"), cc.xy(1, y));
            infoPB.add(UIHelper.createLabel(System.getProperty("java.version")), cc.xy(3, y));
            y += 2;
        }

        String txt = getAboutText(appName, appVersion);
        JLabel txtLbl = createLabel(txt);
        txtLbl.setFont(UIRegistry.getDefaultFont());

        final JEditorPane txtPane = new JEditorPane("text/html", txt);
        txtPane.setEditable(false);
        txtPane.setBackground(new JPanel().getBackground());

        PanelBuilder pb = new PanelBuilder(new FormLayout("p,20px,f:min(400px;p):g,10px,8px,10px,p:g", "f:p:g"));

        pb.add(iconPB.getPanel(), cc.xy(1, 1));
        pb.add(txtPane, cc.xy(3, 1));
        Color bg = getBackground();

        if (hasContext) {
            pb.add(new VerticalSeparator(bg.darker(), bg.brighter()), cc.xy(5, 1));
            pb.add(infoPB.getPanel(), cc.xy(7, 1));
        }

        pb.setDefaultDialogBorder();

        String title = getResourceString("Specify.ABOUT");//$NON-NLS-1$
        CustomDialog aboutDlg = new CustomDialog(topFrame, title + " " + appName, true, CustomDialog.OK_BTN, //$NON-NLS-1$
                pb.getPanel());
        String okLabel = getResourceString("Specify.CLOSE");//$NON-NLS-1$
        aboutDlg.setOkLabel(okLabel);

        aboutDlg.createUI();
        aboutDlg.pack();

        // for some strange reason I can't get the dialog to size itself correctly
        Dimension size = aboutDlg.getSize();
        size.height += 120;
        aboutDlg.setSize(size);

        txtPane.addHyperlinkListener(new HyperlinkListener() {
            public void hyperlinkUpdate(HyperlinkEvent event) {
                if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                    try {
                        AttachmentUtils.openURI(event.getURL().toURI());

                    } catch (Exception e) {
                        edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    }
                }
            }
        });

        UIHelper.centerAndShow(aboutDlg);
    }

    /**
     * Returns a standard String for the about box
     * @param appNameArg the application name  
     * @param appVersionArg the application version
     * @return the about string
     */
    public static String getAboutText(final String appNameArg, final String appVersionArg) {
        return "<html><font face=\"sans-serif\" size=\"11pt\">" + appNameArg + " " + appVersionArg + //$NON-NLS-1$ //$NON-NLS-2$
                "<br><br>Specify Software Project<br>" + //$NON-NLS-1$
                "Biodiversity Institute<br>University of Kansas<br>1345 Jayhawk Blvd.<br>Lawrence, KS  USA 66045<br><br>" //$NON-NLS-1$
                + "<a href=\"http://www.specifysoftware .org\">www.specifysoftware.org</a>" + "<br><a href=\"mailto:specify@ku.edu\">specify@ku.edu</a><br>" + "<p>The Specify Software Project is " + "funded by the Advances in Biological Informatics Program, " + "U.S. National Science Foundation  (Award DBI-0446544 and earlier awards).<br><br>" + "Specify 6.0 Copyright \u00A9 2009 University of Kansas Center for Research. "
                + "Specify comes with ABSOLUTELY NO WARRANTY.<br><br>" + //$NON-NLS-1$
                "This is free software licensed under GNU General Public License 2 (GPL2).</P></font></html>"; //$NON-NLS-1$

    }

    /* (non-Javadoc)
     * @see edu.ku.brc.af.core.FrameworkAppIFace#doExit(boolean)
     */
    @Override
    public boolean doExit(boolean doAppExit) {
        return true;
    }

    /**
     * @return the statusField
     */
    public JStatusBar getStatusField() {
        return statusField;
    }

    protected String getTitle() {
        String resAppVersion = UIRegistry.getAppVersion();
        ;
        if (StringUtils.isNotEmpty(resAppVersion)) {
            appVersion = resAppVersion;
        }

        return getTitle(appVersion, appBuildVersion, appName);
    }

    /**
     * If the version number is '(Unknown)' then it wasn't installed with install4j.
     * @return the title for Specify which may include the version number.
     */
    public static String getTitle(final String appVersionStr, final String appBuildVersionStr,
            final String appNameStr) {
        String title = "";
        String resAppVersion = UIRegistry.getAppVersion();
        if (StringUtils.isNotEmpty(resAppVersion)) {
            title = appNameStr + " " + appVersionStr; //$NON-NLS-1$
        } else {
            title = appNameStr + " " + appVersionStr + "  - " + appBuildVersionStr; //$NON-NLS-1$ //$NON-NLS-2$
        }
        if (UIRegistry.isEmbedded()) {
            title += " (EZDB)";

        } else if (UIRegistry.isMobile()) {
            title += " (Mobile)";
        }
        return title;
    }

    /**
     * Bring up the PPApp demo by showing the frame (only applicable if coming up
     * as an application, not an applet);
     */
    public void showApp() {
        JFrame f = getFrame();
        f.setTitle(getTitle());
        f.getContentPane().add(this, BorderLayout.CENTER);
        f.pack();

        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                doExit(true);
            }
        });

        UIHelper.centerWindow(f);
        Rectangle r = f.getBounds();
        int x = AppPreferences.getLocalPrefs().getInt("APP.X", r.x);
        int y = AppPreferences.getLocalPrefs().getInt("APP.Y", r.y);
        int w = AppPreferences.getLocalPrefs().getInt("APP.W", r.width);
        int h = AppPreferences.getLocalPrefs().getInt("APP.H", r.height);
        UIHelper.positionAndFitToScreen(f, x, y, w, h);

        f.setVisible(true);
    }

    /**
     * Returns the frame instance
     */
    public JFrame getFrame() {
        return topFrame;
    }

    /**
     * Returns the menubar
     */
    public JMenuBar getMenuBar() {
        return menuBar;
    }

    /**
     * Set the status
     */
    public void setStatus(final String str) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                getAppInstance().getStatusField().setText(str);
            }
        });
    }

    /**
     * 
     */
    protected static void setupDefaultFonts() {
        Font labelFont = (createLabel("")).getFont(); //$NON-NLS-1$
        Font defaultFont;
        if (!UIHelper.isMacOS()) {
            defaultFont = labelFont;
        } else {
            //if (labelFont.getSize() == 13)
            //{
            //    defaultFont = labelFont.deriveFont((float)labelFont.getSize()-2);
            //} else
            {
                defaultFont = labelFont;
            }
        }
        BaseTask.setToolbarBtnFont(defaultFont); // For ToolbarButtons
        RolloverCommand.setDefaultFont(defaultFont);
    }

    /**
     * Restarts the app with a new or old database and user name and creates the core app UI.
     * @param window the login window
     * @param databaseNameArg the database name
     * @param userNameArg the user name
     * @param startOver tells the AppContext to start over
     * @param firstTime indicates this is the first time in the app and it should create all the UI for the core app
     */
    public void restartApp(final Window window, final String databaseNameArg, final String userNameArg,
            final boolean startOver, final boolean firstTime) {

    }

    //---------------------------------------------------------
    // DatabaseLoginListener Interface
    //---------------------------------------------------------

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.db.DatabaseLoginListener#loggedIn(java.awt.Window, java.lang.String, java.lang.String)
     */
    public void loggedIn(final Window window, final String databaseNameArg, final String userNameArg) {
        log.debug("loggedIn - database[" + databaseNameArg + "] username[" + userNameArg + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        boolean firstTime = this.databaseName == null;

        this.databaseName = databaseNameArg;
        this.userName = userNameArg;

        // This is used to fill who editted the object
        FormHelper.setCurrentUserEditStr(userNameArg);

        AppPreferences.setConnectedToDB(true);

        restartApp(window, databaseName, userName, false, firstTime);

        statusField.setSectionText(2, userName);
        statusField.setSectionToolTipText(2,
                DBTableIdMgr.getInstance().getTitleForId(SpecifyUser.getClassTableId()));

    }

    /**
     * Sets the Database Name and the Collection Name into the Status Bar. 
     */
    protected void setDatabaseNameAndCollection() {
        AppContextMgr mgr = AppContextMgr.getInstance();
        String disciplineName = mgr.getClassObject(Discipline.class).getName();
        String collectionName = mgr.getClassObject(Collection.class) != null
                ? mgr.getClassObject(Collection.class).getCollectionName()
                : ""; //$NON-NLS-1$ //$NON-NLS-2$
        statusField.setSectionText(0, disciplineName);
        statusField.setSectionText(1, collectionName);

        statusField.setSectionToolTipText(0,
                DBTableIdMgr.getInstance().getTitleForId(Discipline.getClassTableId()));
        statusField.setSectionToolTipText(1,
                DBTableIdMgr.getInstance().getTitleForId(Collection.getClassTableId()));

        AppPreferences.getLocalPrefs().put("CURRENT_DB", databaseName);
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.db.DatabaseLoginListener#cancelled()
     */
    public void cancelled() {
        System.exit(0);
    }

    /**
     * Reads Local Preferences for the Locale setting.
     */
    public static void adjustLocaleFromPrefs() {
        String language = AppPreferences.getLocalPrefs().get("locale.lang", null); //$NON-NLS-1$
        if (language != null) {
            String country = AppPreferences.getLocalPrefs().get("locale.country", null); //$NON-NLS-1$
            String variant = AppPreferences.getLocalPrefs().get("locale.var", null); //$NON-NLS-1$

            Locale prefLocale = new Locale(language, country, variant);

            Locale.setDefault(prefLocale);
            UIRegistry.setResourceLocale(prefLocale);
        }

        try {
            ResourceBundle.getBundle("resources", Locale.getDefault()); //$NON-NLS-1$

        } catch (MissingResourceException ex) {
            Locale.setDefault(Locale.ENGLISH);
            UIRegistry.setResourceLocale(Locale.ENGLISH);
        }
    }

    /**
     * @return the appVersion
     */
    public String getAppVersion() {
        return appVersion;
    }

    /**
     * @return the appBuildVersion
     */
    public String getAppBuildVersion() {
        return appBuildVersion;
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.ui.CommandListener#doCommand(edu.ku.brc.ui.CommandAction)
     */
    @Override
    public void doCommand(final CommandAction cmdAction) {
        if (cmdAction.isType(BaseTask.APP_CMD_TYPE)) {
            if (cmdAction.isAction(BaseTask.APP_REQ_RESTART)) {
                UIRegistry.writeGlassPaneMsg(getResourceString("Specify.RESET_ENV"), 24);

                SwingWorker workerThread = new SwingWorker() {
                    @Override
                    public Object construct() {
                        restartApp(null, databaseName, userName, true, false);
                        return null;
                    }

                    @Override
                    public void finished() {
                        UIRegistry.clearGlassPaneMsg();
                    }
                };

                // start the background task
                workerThread.start();

            } else if (cmdAction.isAction(BaseTask.APP_REQ_EXIT)) {
                doExit(true);

            } else if (cmdAction.isAction("CheckForUpdates")) {
                checkForUpdates();
            }
        }
    }

    /**
     * @param args
     */
    public static void processArgs(final String[] args) {
        //log.debug("********* Current ["+(new File(".").getAbsolutePath())+"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

        UIRegistry.setEmbeddedDBPath(UIRegistry.getDefaultEmbeddedDBPath()); // on the local machine

        for (String s : args) {
            String[] pairs = s.split("="); //$NON-NLS-1$
            if (pairs.length == 2) {
                if (pairs[0].startsWith("-D")) //$NON-NLS-1$
                {
                    //System.err.println("["+pairs[0].substring(2, pairs[0].length())+"]["+pairs[1]+"]");
                    System.setProperty(pairs[0].substring(2, pairs[0].length()), pairs[1]);
                }
            } else {
                String symbol = pairs[0].substring(2, pairs[0].length());
                //System.err.println("["+symbol+"]");
                System.setProperty(symbol, symbol);
            }
        }

        // Now check the System Properties
        String appDir = System.getProperty("appdir");
        if (StringUtils.isNotEmpty(appDir)) {
            UIRegistry.setDefaultWorkingPath(appDir);
        }

        String appdatadir = System.getProperty("appdatadir");
        if (StringUtils.isNotEmpty(appdatadir)) {
            UIRegistry.setBaseAppDataDir(appdatadir);
        }

        String mobile = System.getProperty("mobile");
        if (StringUtils.isNotEmpty(mobile)) {
            UIRegistry.setMobile(true);
            DBConnection.setIsEmbeddedDB(true);
        }

        String embeddedStr = System.getProperty("embedded");
        if (StringUtils.isNotEmpty(embeddedStr)) {
            UIRegistry.setEmbedded(true);
            DBConnection.setIsEmbeddedDB(true);
        }

        String embeddeddbdir = System.getProperty("embeddeddbdir");
        if (StringUtils.isNotEmpty(embeddeddbdir)) {
            UIRegistry.setEmbeddedDBPath(embeddeddbdir);
        } else {
            UIRegistry.setEmbeddedDBPath(UIRegistry.getDefaultEmbeddedDBPath()); // on the local machine
        }
    }

    // *******************************************************
    // *****************   Static Methods  *******************
    // *******************************************************

    /**
     *
     * @return the specify app object
     */
    public static AppBase getAppInstance() {
        return appInstance;
    }
}