package org.korsakow.ide;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.Thread.UncaughtExceptionHandler;
import java.sql.SQLException;
import javax.swing.JOptionPane;
import javax.swing.JWindow;
import javax.swing.Timer;
import org.apache.log4j.Logger;
import org.dsrg.soenea.service.threadLocal.DbRegistry;
import org.korsakow.ide.controller.ApplicationAdapter;
import org.korsakow.ide.lang.LanguageBundle;
import org.korsakow.ide.ui.ProjectExplorer;
import org.korsakow.ide.ui.SplashPage;
import org.korsakow.ide.util.Platform;
import org.korsakow.ide.util.UIUtil;
import org.korsakow.services.encoders.image.ImageEncoderFactory;
import org.korsakow.services.encoders.image.JavaImageIOImageEncoder;
import org.korsakow.services.encoders.sound.SoundEncoderFactory;
import org.korsakow.services.encoders.sound.lame.plaf.LameEncoderOSX;
import org.korsakow.services.encoders.sound.lame.plaf.LameEncoderWin32;
import org.korsakow.services.encoders.video.VideoEncoderFactory;
import org.korsakow.services.encoders.video.ffmpeg.plaf.FFMpegEncoderOSX;
import org.korsakow.services.encoders.video.ffmpeg.plaf.FFMpegEncoderWin32;
import org.korsakow.services.updater.Updater;
import quicktime.QTException;
import quicktime.QTSession;
//import com.apple.eawt.ApplicationEvent;
//import com.apple.eawt.ApplicationListener;
public class Main {
/**
* Introduced because ApplicationShutdownListener is added as a weak reference
*/
private static Main main;
public static void main(String[] args) throws Exception {
main = new Main(args);
}
private class ApplicationShutdownListener extends ApplicationAdapter implements Runnable
{
@Override
public void onApplicationShutdown() {
// do later so that other shutdown listeners can do their stuff
UIUtil.runUITaskLater(this);
}
public void run() {
try {
shutdown();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
}
}
private final ApplicationShutdownListener applicationShutdownListener = new ApplicationShutdownListener();
public Main(String[] args) throws Exception {
if (Platform.getOS() == Platform.OS.UNKNOWN ||
Platform.getArch() == Platform.Arch.UNKNOWN ||
Platform.getArch() == Platform.Arch.POWERPC)
{
JOptionPane.showMessageDialog(null,
LanguageBundle.getString("general.errors.unsupportedplatform.message",
Platform.getOS().getCanonicalName(),
Platform.getArch().getCanonicalName()),
LanguageBundle.getString("general.errors.unsupportedplatform.title"),
JOptionPane.ERROR_MESSAGE);
}
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
// These preferences are best set on init of the application
if ( Platform.getOS() == Platform.OS.MAC ) {
// System.setProperty("apple.laf.useScreenMenuBar", "true"); // removed per #840
System.setProperty("com.apple.mrj.application.apple.menu.about.name",
"Korsakow");
}
final Exception[] remoteException = new SQLException[1];
Thread.currentThread().setUncaughtExceptionHandler(
new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread,
Throwable exception) {
Logger.getLogger(Application.class)
.error("", exception);
}
});
setup();
Logger.getLogger(Main.class).info("CommandLine Arguments");
for (String arg : args) {
Logger.getLogger(Main.class).info("\t" + arg + "\n");
}
UIUtil.runUITaskNowThrow(new UIUtil.RunnableThrow() {
public void run() {
UIUtil.setUpLAF();
}
});
final JWindow splashDialog = new JWindow();
UIUtil.runUITaskNowThrow(new UIUtil.RunnableThrow() {
public void run() {
splashDialog.setAlwaysOnTop(true);
SplashPage page = new SplashPage();
page.setUUIDVisible(false);
splashDialog.add(page);
splashDialog.pack();
UIUtil.centerOnScreen(splashDialog);
}
});
UIUtil.runUITaskNowThrow(new UIUtil.RunnableThrow(){
public void run() throws Throwable {
// doing this separately avoids an issue where the splash shows up unpainted for a second
splashDialog.setVisible(true);
splashDialog.toFront();
}
});
UIUtil.runUITaskNowThrow(new UIUtil.RunnableThrow() {
public void run() throws Throwable {
long beforeTime = System.currentTimeMillis();
Application.initializeInstance();
final Application app = Application.getInstance();
app.addApplicationListener(applicationShutdownListener);
final ProjectExplorer explorer = app.showProjectExplorer();
UIUtil.centerOnScreen(explorer);
long afterTime = System.currentTimeMillis();
long delta = afterTime - beforeTime;
long minTime = 2000;
long timerTime = Math.max(1, minTime-delta);
Timer timer = new Timer((int)timerTime, new ActionListener() {
public void actionPerformed(ActionEvent event) {
splashDialog.dispose();
explorer.setVisible(true);
app.getProjectExplorerController().loadDefaultProject();
Updater.checkAsynch();
}
});
timer.setRepeats(false);
timer.start();
}
});
}
private void shutdownLibs() throws Exception {
Logger.getLogger(Main.class).info("shutdown libs");
// QT is pretty quirky, and for example might keep processes hanging
// around if the shutdown isnt complete
// so we try our best to make sure each part of the shutdown is
// attempted
try {
QTSession.exitMovies();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
try {
QTSession.close();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
}
private void shutdown() throws Exception {
Logger.getLogger(Main.class).info("shutdown begin");
try {
shutdownUoW();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
try {
DataRegistry.getConnection().commit();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
;
try {
shutdownLibs();
} catch (Exception e) {
Logger.getLogger(Main.class).error("", e);
}
Logger.getLogger(Main.class).info(
"shutdown complete (this should be the last item logged)");
System.exit(0);
}
private void shutdownUoW() throws Exception {
final Exception[] remoteException = new SQLException[1];
Runnable runnable = new Runnable() {
public void run() {
try {
DbRegistry.getDbConnection().rollback();
} catch (SQLException e) {
Logger.getLogger(Application.class).error("", e);
remoteException[0] = e;
return;
}
}
};
UIUtil.runUITaskNow(runnable);
if (remoteException[0] != null)
throw remoteException[0];
}
private void setup() throws Exception {
// setup the UUID as early as possible as it is used in error reporting and logging.
Application.getUUID(); // side effect causes the UUID to be persisted.
setupLogging();
setupPlatform();
UIUtil.runUITaskNow(new Runnable() { public void run() { try {
setupLibs();
} catch (QTException e) {
throw new RuntimeException(e);
} } });
}
public static void setupLogging() {
System.setProperty("org.korsakow.log.filename", Application.getLogfilename());
Logger.getLogger(Main.class).info(Build.getAboutString());
Logger.getLogger(Main.class).info(String.format("Java: JVM %s, JRE %s, ", System.getProperty("java.version"), System.getProperty("java.class.version")));
Logger.getLogger(Main.class).info(String.format("Platform: %s %s\n\tDetected as: Operating System: %s, Architechture: %s", Platform.getArchString(), Platform.getOSString(), Platform.getOS().getCanonicalName(), Platform.getArch().getCanonicalName()));
Logger.getLogger(Main.class).info(String.format("UUID: %s", Application.getUUID()));
}
private static void setupPlatform() {
setupPlatformEncoders();
}
public static void setupPlatformEncoders() {
switch (Platform.getOS()) {
case MAC:
SoundEncoderFactory.getDefaultFactory().addEncoder(
new LameEncoderOSX.LameEncoderOSXDescription());
VideoEncoderFactory.addEncoder(
new FFMpegEncoderOSX.FFMpegEncoderOSXDescription());
break;
case WIN:
// FontEncoderFactory.getDefaultFactory().addEncoder(new
// SwfMillEncoderOSX.SwfMillEncoderWin32XDescription());
SoundEncoderFactory.getDefaultFactory().addEncoder(
new LameEncoderWin32.LameEncoderWin32Description());
VideoEncoderFactory.addEncoder(
new FFMpegEncoderWin32.FFMpegEncoderWin32Description());
break;
case NIX:
default:
System.out.println("Platform specific features not yet supported");
break;
}
ImageEncoderFactory.addEncoder(new JavaImageIOImageEncoder.JavaImageIOEncoderDescription());
}
private static void setupLibs() throws QTException {
try {
QTSession.open();
} catch (UnsatisfiedLinkError e) {
JOptionPane.showMessageDialog(null,
"Korsakow requires quicktime to be installed in order to run.",
"Quicktime was not found",
JOptionPane.ERROR_MESSAGE);
throw e;
} catch (NoClassDefFoundError e) {
JOptionPane.showMessageDialog(null,
"Korsakow requires quicktime to be installed in order to run.",
"Quicktime was not found",
JOptionPane.ERROR_MESSAGE);
throw e;
}
}
}