/*******************************************************************************
* GenPlay, Einstein Genome Analyzer
* Copyright (C) 2009, 2014 Albert Einstein College of Medicine
*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu>
* Nicolas Fourel <nicolas.fourel@einstein.yu.edu>
* Eric Bouhassira <eric.bouhassira@einstein.yu.edu>
*
* Website: <http://genplay.einstein.yu.edu>
******************************************************************************/
package edu.yu.einstein.genplay.gui.launcher;
import java.awt.EventQueue;
import java.io.File;
import java.io.InputStream;
import java.util.concurrent.CountDownLatch;
import javax.swing.JOptionPane;
import javax.swing.ToolTipManager;
import edu.yu.einstein.genplay.core.manager.application.ConfigurationManager;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.dataStructure.chromosome.Chromosome;
import edu.yu.einstein.genplay.dataStructure.genome.Assembly;
import edu.yu.einstein.genplay.dataStructure.genome.Clade;
import edu.yu.einstein.genplay.dataStructure.genome.Genome;
import edu.yu.einstein.genplay.dataStructure.genomeWindow.SimpleGenomeWindow;
import edu.yu.einstein.genplay.exception.ExceptionManager;
import edu.yu.einstein.genplay.gui.OSIntegration.OSXIntegrator;
import edu.yu.einstein.genplay.gui.OSIntegration.X11Integrator;
import edu.yu.einstein.genplay.gui.action.multiGenome.synchronization.MGASynchronizing;
import edu.yu.einstein.genplay.gui.action.project.PAInitMGManager;
import edu.yu.einstein.genplay.gui.action.project.PAInitManagers;
import edu.yu.einstein.genplay.gui.action.project.PALoadProject;
import edu.yu.einstein.genplay.gui.dialog.quickViewDialog.QuickViewDialog;
import edu.yu.einstein.genplay.gui.fileFilter.GenPlayTrackFilter;
import edu.yu.einstein.genplay.gui.mainFrame.MainFrame;
import edu.yu.einstein.genplay.gui.projectFrame.ProjectFrame;
import edu.yu.einstein.genplay.util.Utils;
/**
* This class loads GenPlay with a welcome screen.
* Then, the main frame is loaded.
* @author Nicolas Fourel
* @author Julien Lajugie
*/
public class Launcher {
/**
* This class loads the rest of the project (multigenome manager and the tracks).
* The loading of the Multi Genome manager has to be done before the loading of the tracks.
* This is why both processes are within a same thread managing a waiting time between them.
*
* @author Nicolas Fourel
*/
private static class LoadingThread extends Thread {
@Override
public void run() {
PAInitMGManager initMGAction = new PAInitMGManager();
CountDownLatch latch = new CountDownLatch(1);
initMGAction.setLatch(latch);
initMGAction.actionPerformed(null);
try {
latch.await();
} catch (InterruptedException e) {
ExceptionManager.getInstance().caughtException(e);
}
PALoadProject load = new PALoadProject();
load.setSkipFileSelection(true);
load.actionPerformed(null);
}
}
/**
* Tooltip dismissal delay value for the entire program
*/
private static final int TOOLTIP_DISMISS_DELAY = Integer.MAX_VALUE;
/**
* Tooltip initial delay value for the entire program
*/
private static final int TOOLTIP_INITIAL_DELAY = 500;
/**
* This constant can be set to a project file path in the resource folder of the jar.
* In this case this project will be directly loaded when GenPlay starts.
*/
private static final String DEMO_PROJECT_PATH = null;
/**
* Initialize the exception manager
*/
private static void initializeExceptionManagement () {
// Set the uncaught exception handler for GenPlay
Thread.setDefaultUncaughtExceptionHandler(ExceptionManager.getInstance());
// Set the exception manager options
ExceptionManager.getInstance().enablePrintReport(false);
ExceptionManager.getInstance().enablePrintStackTrace(true);
}
/**
* This method is used by the ProjectFrame after closing
* to initiate a new project.
*/
public static void initiateNewProject() {
ProjectFrame projectFrame = ProjectFrame.getInstance();
Clade clade = projectFrame.getSelectedClade();
Genome genome = projectFrame.getSelectedGenome();
Assembly assembly = projectFrame.getSelectedAssembly();
assembly.setChromosomeList(projectFrame.getSelectedChromosomes());
ProjectManager projectManager = ProjectManager.getInstance();
projectManager.setProjectName(projectFrame.getProjectName());
projectManager.setProjectScorePrecision(projectFrame.getProjectScorePrecision());
projectManager.setCladeName(clade.getName());
projectManager.setGenomeName(genome.getName());
projectManager.setAssembly(assembly);
projectManager.updateChromosomeList();
projectFrame.setVisible(false);
// Initializes the genome window manager
Chromosome currentChromosome = ProjectManager.getInstance().getProjectChromosomes().get(0);
SimpleGenomeWindow genomeWindow = new SimpleGenomeWindow(currentChromosome, 1, currentChromosome.getLength() + 1);
ProjectManager.getInstance().getProjectWindow().setGenomeWindow(genomeWindow);
// Set the project as a multi genome project before any call of the MainFrame (some graphical elements check it out in order to be displayed)
if (!projectFrame.isSingleProject()) {
ProjectManager.getInstance().setMultiGenomeProject(true);
}
// reinit the MainFrame if needed (in the case where the user chose the new project option from the mainframe)
MainFrame.reinit();
// starts the main frame of the application
MainFrame.getInstance().setVisible(true);
MainFrame.getInstance().initStatusBarForFirstUse();
// generate the multi-genome manager if the user starts a multi-genome project
if (!projectFrame.isSingleProject()) {
MGASynchronizing multiGenome = new MGASynchronizing();
multiGenome.setGenomeFileAssociation(projectFrame.getGenomeFileAssociation());
multiGenome.actionPerformed(null);
} else {
projectManager.setMultiGenomeProject(false);
}
}
/**
* Loads a file using a file object.
* First initializes the managers and then load the file.
* @param file the file
*/
private static void loadFile (File file) {
PAInitManagers init = new PAInitManagers();
init.setFile(file);
loadProject(init);
}
/**
* Loads a file using an input stream.
* First initializes the managers and then load the file.
* @param is the input strean
*/
private static void loadFile (InputStream is) {
PAInitManagers init = new PAInitManagers();
init.setInputStream(is);
loadProject(init);
}
/**
* Loads a project.
*/
private static void loadProject (PAInitManagers initAction) {
initAction.setLoadingFromWelcomeScreen(true);
initAction.actionPerformed(null);
if (initAction.hasBeenInitialized()) {
MainFrame.getInstance().setVisible(true);
LoadingThread thread = new LoadingThread();
thread.start();
} else {
JOptionPane.showMessageDialog(null, initAction.getErrorMessage(), "The project has not been initialized", JOptionPane.WARNING_MESSAGE);
ProjectFrame.getInstance().setVisible(true);
}
}
/**
* Starts the application
* @param args a project file path can be specified. In this case the project
* screen will be skipped and the project file will be directly loaded
*/
public static void main(final String[] args) {
if (Utils.isMacOS()) {
// Handle mac-specific events (if we're running under OS X).
OSXIntegrator.integrateApplication();
} else if (!Utils.isWindowsOS()) {
// set the WM_CLASS property for X11
X11Integrator.setWMClassName();
}
// load the application settings
try {
ConfigurationManager.getInstance().loadConfiguration();
} catch (Exception e) {}
// Initialize the exception manager
initializeExceptionManagement();
// set the tooltip properties
ToolTipManager.sharedInstance().setDismissDelay(TOOLTIP_DISMISS_DELAY);
ToolTipManager.sharedInstance().setInitialDelay(TOOLTIP_INITIAL_DELAY);
//SwingUtilities.invokeLater(new Runnable() {
/*
* Fix for the exception that starts like:
* Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
* at javax.swing.plaf.basic.BasicProgressBarUI.updateSizes(Unknown Source)
* at javax.swing.plaf.basic.BasicProgressBarUI.getBox(Unknown Source)
* at javax.swing.plaf.basic.BasicProgressBarUI.paintString(Unknown Source)
* at javax.swing.plaf.basic.BasicProgressBarUI.paintDeterminate(Unknown Source)
* at javax.swing.plaf.metal.MetalProgressBarUI.paintDeterminate(Unknown Source)
* at javax.swing.plaf.basic.BasicProgressBarUI.paint(Unknown Source)
*
* Found on several website:
* You are probably here, because you searched for the line above in a search engine.
* If you are a Java-Programmer and you get this problem, here is the solution:
* The problem is, that Swing is not thread-safe. You have probably tried to call a method on a Swing-Component from another thread (than the AWT-EventQueue-Thread). You should not do that!
* Methods of Swing-Components should always be called from the EventQueue.
*/
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// if the DEMO_PROJECT_PATH constant has been set it means that we're starting a demo project
boolean isDemo = (DEMO_PROJECT_PATH != null);
// mac only
if (Utils.isMacOS() && (OSXIntegrator.getInstance().getFileToOpen() != null)) {
startProjectFromFile(OSXIntegrator.getInstance().getFileToOpen());
} else if (isDemo) {
startDemoProject();
} else if (args.length == 1) { // if a project file path has been specified to the main method we load this file
File file = new File(args[0]);
startProjectFromFile(file);
} else { // normal execution of the software
startProjectFrame();
}
}
});
}
/**
* This method starts a demo project. The project file needs to be in the resource folder and
* the path to this file must be specified in the DEMO_PROJECT_PATH constant
*/
private static void startDemoProject() {
InputStream is = ProjectFrame.getInstance().getClass().getClassLoader().getResourceAsStream(DEMO_PROJECT_PATH);
try {
loadFile(is);
} catch (Exception e) {
ExceptionManager.getInstance().caughtException(e);
}
}
/**
* Displays the project screen manager which is the first screen of GenPlay.
*/
private static void startProjectFrame() {
//Welcome screen initialization
ProjectFrame projectFrame = ProjectFrame.getInstance();
//Create a new thread to display the welcome screen
projectFrame.initScreen();
}
/**
* This method starts a project from a file.
* @param file project file to load
*/
public static void startProjectFromFile(File file) {
try {
if (Utils.getExtension(file).equals(GenPlayTrackFilter.EXTENSIONS[0])) {
QuickViewDialog.showDialog(file);
} else {
loadFile(file);
}
} catch (Exception e) {
ExceptionManager.getInstance().caughtException(e);
System.out.println("Invalid Project File: The specifed file is not a valid project file");
System.out.println(file.getPath());
}
}
}