package org.phenoscape.main;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.log4j.Logger;
import org.bbop.framework.GUIComponentFactory;
import org.bbop.framework.GUIManager;
import org.bbop.framework.GUITask;
import org.bbop.framework.VetoableShutdownListener;
import org.bbop.framework.dock.LayoutDriver;
import org.bbop.framework.dock.idw.IDWDriver;
import org.jdesktop.swingworker.SwingWorker;
import org.obo.annotation.base.UserOntologyConfiguration;
import org.obo.annotation.view.LogViewComponentFactory;
import org.obo.annotation.view.NativeDockingTheme;
import org.obo.annotation.view.SelectionBridge;
import org.obo.annotation.view.TermInfoComponentFactory;
import org.obo.app.swing.BlockingProgressDialog;
import org.obo.app.swing.WindowSizePrefsSaver;
import org.obo.app.util.CrossPlatform;
import org.oboedit.gui.factory.SearchComponentFactory;
import org.oboedit.gui.factory.SearchResultsComponentFactory;
import org.oboedit.gui.tasks.DefaultGUIStartupTask;
import org.phenoscape.controller.OntologyController;
import org.phenoscape.controller.PhenexController;
import org.phenoscape.view.AnnotationCheckerComponentFactory;
import org.phenoscape.view.CharacterMatrixComponentFactory;
import org.phenoscape.view.CharacterTableComponentFactory;
import org.phenoscape.view.ConsistencyReviewComponentFactory;
import org.phenoscape.view.DataSetComponentFactory;
import org.phenoscape.view.MenuFactory;
import org.phenoscape.view.ORBPreferencesComponentFactory;
import org.phenoscape.view.OntologyPreferencesComponentFactory;
import org.phenoscape.view.PhenotypeProposalComponentFactory;
import org.phenoscape.view.PhenotypeTableComponentFactory;
import org.phenoscape.view.SpecimenTableComponentFactory;
import org.phenoscape.view.StateSupportComponentFactory;
import org.phenoscape.view.StateSupportInKBComponentFactory;
import org.phenoscape.view.StateTableComponentFactory;
import org.phenoscape.view.TaxonTableComponentFactory;
/**
* This startup task does all the work of starting up Phenex.
* @author Jim Balhoff
*/
public class PhenexStartupTask extends DefaultGUIStartupTask {
private PhenexController controller;
private UserOntologyConfiguration ontologyConfiguration;
@Override
protected Collection<GUIComponentFactory<?>> getDefaultComponentFactories() {
Collection<GUIComponentFactory<?>> factories = new ArrayList<GUIComponentFactory<?>>();
factories.add(new DataSetComponentFactory(this.controller));
factories.add(new CharacterTableComponentFactory(this.controller));
factories.add(new StateTableComponentFactory(this.controller));
factories.add(new PhenotypeTableComponentFactory(this.controller));
factories.add(new AnnotationCheckerComponentFactory(this.controller));
factories.add(new ConsistencyReviewComponentFactory(this.controller));
factories.add(new StateSupportComponentFactory(this.controller));
factories.add(new StateSupportInKBComponentFactory(this.controller));
factories.add(new PhenotypeProposalComponentFactory(this.controller));
factories.add(new TaxonTableComponentFactory(this.controller));
factories.add(new SpecimenTableComponentFactory(this.controller));
factories.add(new CharacterMatrixComponentFactory(this.controller));
factories.add(new OntologyPreferencesComponentFactory(this.ontologyConfiguration));
factories.add(new ORBPreferencesComponentFactory());
factories.add(new TermInfoComponentFactory(this.controller.getOntologyCoordinator()));
//factories.add(new PhenoteOntologyTreeEditorFactory());
factories.add(new SearchComponentFactory() {
@Override
public FactoryCategory getCategory() {
return FactoryCategory.ONTOLOGY;
}
});
factories.add(new SearchResultsComponentFactory());
factories.add(new LogViewComponentFactory());
return factories;
}
@Override
protected void configureLogging() {
//logging is configured via the log4j config file in the classpath
}
@Override
protected void configureUI() {
try {
final String lookAndFeelClassName = UIManager.getSystemLookAndFeelClassName();
if (CrossPlatform.getCurrentPlatform().equals(CrossPlatform.Platform.MAC)) {
// We are running on Mac OS X - use the Quaqua look and feel
System.setProperty("apple.laf.useScreenMenuBar", "true");
UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
} else {
// We are on some other platform, use the system look and feel
UIManager.setLookAndFeel(lookAndFeelClassName);
}
} catch (ClassNotFoundException e) {
log().error("Look and feel class not found", e);
} catch (InstantiationException e) {
log().error("Could not instantiate look and feel", e);
} catch (IllegalAccessException e) {
log().error("Error setting look and feel", e);
} catch (UnsupportedLookAndFeelException e) {
log().error("Look and feel not supported", e);
}
}
@Override
protected void configureSystem() {
super.configureSystem();
this.ontologyConfiguration = new UserOntologyConfiguration();
final SwingWorker<OntologyController, Void> ontologyLoader = new SwingWorker<OntologyController, Void>() {
@Override
protected OntologyController doInBackground() {
return new OntologyController(ontologyConfiguration);
}
};
// you would expect that displaying the progress dialog would make the splash screen go away, but it doesn't
this.flashJFrameToMakeSplashScreenGoAway();
final BlockingProgressDialog<OntologyController, Void> dialog = new BlockingProgressDialog<OntologyController, Void>(ontologyLoader, "Phenex is checking for ontology updates. It may take some time to download and configure ontologies.");
dialog.setTitle("Launching " + this.getAppName());
dialog.setSize(400, 150);
dialog.setLocationRelativeTo(null);
dialog.run();
try {
this.controller = new PhenexController(ontologyLoader.get());
} catch (InterruptedException e) {
log().fatal("Failed to create ontology controller", e);
GUIManager.exit(1);
} catch (ExecutionException e) {
log().fatal("Failed to create ontology controller", e);
GUIManager.exit(1);
}
this.controller.setAppName(this.getAppName());
}
@Override
protected String getAppID() {
return "Phenex";
}
@Override
protected String getAppName() {
return "Phenex";
}
@Override
protected Action getAboutAction() {
//TODO make an about panel
return new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
}
};
}
@Override
protected JFrame createFrame() {
final JFrame frame = super.createFrame();
frame.setTitle(getAppName());
// the window prefs saver is not currently working because the BBOP MainFrame is trying to be too smart
new WindowSizePrefsSaver(frame, this.getClass().getName() + "mainwindow");
return frame;
}
@Override
protected void showFrame() {
// BBOP centers and makes frame a certain size - we are overriding this
GUIManager.getManager().getFrame().setVisible(true);
}
@Override
protected LayoutDriver createLayoutDriver() {
final LayoutDriver driver = super.createLayoutDriver();
if (driver instanceof IDWDriver) {
((IDWDriver)driver).setCustomTheme(new NativeDockingTheme());
}
driver.setSaveLayoutOnExit(false);
return driver;
}
@Override
protected String getPerspectiveResourceDir() {
return "org/phenoscape/view/layouts";
}
@Override
protected String getDefaultPerspectiveResourcePath() {
if (getPerspectiveResourceDir() != null)
return getPerspectiveResourceDir() + "/default.idw";
else
return null;
}
@Override
public File getPrefsDir() {
return CrossPlatform.getUserPreferencesFolder(this.getAppID());
}
@Override
protected void installSystemListeners() {
GUIManager.addVetoableShutdownListener(new VetoableShutdownListener() {
@Override
public boolean willShutdown() {
return controller.canCloseDocument();
}
});
}
@Override
protected void doOtherInstallations() {
super.doOtherInstallations();
new SelectionBridge(this.controller.getOntologyCoordinator().getSelectionManager()).install();
}
@Override
protected Collection<? extends JMenuItem> getDefaultMenus() {
return (new MenuFactory(this.controller)).createMenus();
}
@Override
protected Collection<GUITask> getDefaultTasks() {
// OBO-Edit startup task adds some things we don't want
// hopefully none of these tasks are needed for operations in Phenex
return new ArrayList<GUITask>();
}
private void flashJFrameToMakeSplashScreenGoAway() {
final JFrame frame = new JFrame();
frame.setVisible(true);
frame.setVisible(false);
}
private Logger log() {
return Logger.getLogger(this.getClass());
}
}