/*
* Main.java
* Eisenkraut
*
* Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.eisenkraut;
import de.sciss.app.DocumentHandler;
import de.sciss.common.AppWindow;
import de.sciss.common.BasicApplication;
import de.sciss.common.BasicDocument;
import de.sciss.common.BasicMenuFactory;
import de.sciss.common.BasicWindowHandler;
import de.sciss.common.ProcessingThread;
import de.sciss.eisenkraut.gui.AudioFileInfoPalette;
import de.sciss.eisenkraut.gui.ControlRoomFrame;
import de.sciss.eisenkraut.gui.IOSetupFrame;
import de.sciss.eisenkraut.gui.MainFrame;
import de.sciss.eisenkraut.gui.MenuFactory;
import de.sciss.eisenkraut.gui.ObserverPalette;
import de.sciss.eisenkraut.gui.PrefsFrame;
import de.sciss.eisenkraut.gui.WelcomeScreen;
import de.sciss.eisenkraut.io.PrefCacheManager;
import de.sciss.eisenkraut.net.OSCRoot;
import de.sciss.eisenkraut.net.OSCRouter;
import de.sciss.eisenkraut.net.OSCRouterWrapper;
import de.sciss.eisenkraut.net.RoutedOSCMessage;
import de.sciss.eisenkraut.net.SuperColliderClient;
import de.sciss.eisenkraut.render.FilterDialog;
import de.sciss.eisenkraut.util.PrefsUtil;
import de.sciss.gui.HelpFrame;
import de.sciss.io.CacheManager;
import de.sciss.io.IOUtil;
import de.sciss.submin.Submin;
import de.sciss.util.Flag;
import javax.swing.*;
import javax.swing.plaf.metal.MetalLookAndFeel;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;
/**
* The <code>Main</code> class contains the java VM
* startup static <code>main</code> method which
* creates a new instance of <code>Main</code>. This instance
* will initialize localized strings (ResourceBundle),
* Preferences, the <code>transport</code>, the <code>menuFactory</code>
* object (a prototype of the applications menu and its
* actions).
* <p>
* Common components are created and registered:
* <code>SuperColliderFrame</code>, <code>TransportPalette</code>,
* <code>ObserverPalette</code>, and <code>DocumentFrame</code>.
* <p>
* The <code>Main</code> class extends the <code>Application</code>
* class from the <code>de.sciss.app</code> package.
*/
public class Main
extends BasicApplication
implements OSCRouter {
private static final String APP_NAME = "Eisenkraut";
/*
* Current version of the application. This is stored
* in the preferences file.
*
* @todo should be saved in the session file as well
*/
private static final double APP_VERSION = 1.3;
/**
* Enables / disables event dispatching debugging
*/
// public static final boolean DEBUG_EVENTS = false;
/*
* The MacOS file creator string.
*/
private static final String CREATOR = "EisK";
/**
* Value for add/getComponent(): the preferences frame
*
* @see #getComponent( Object )
*/
public static final Object COMP_PREFS = PrefsFrame.class.getName();
/**
* Value for add/getComponent(): the observer palette
*
* @see #getComponent( Object )
*/
public static final Object COMP_OBSERVER = ObserverPalette.class.getName();
/**
* Value for add/getComponent(): input/output setup
*
* @see #getComponent( Object )
*/
public static final Object COMP_IOSETUP = IOSetupFrame.class.getName();
/**
* Value for add/getComponent(): the filter-process dialog
*
* @see #getComponent( Object )
*/
public static final Object COMP_FILTER = FilterDialog.class.getName();
/**
* Value for add/getComponent(): the main log frame
*
* @see #getComponent( Object )
*/
public static final Object COMP_MAIN = MainFrame.class.getName();
/**
* Value for add/getComponent(): the control room frame
*
* @see #getComponent( Object )
* @see de.sciss.eisenkraut.gui.ControlRoomFrame
*/
public static final Object COMP_CTRLROOM = ControlRoomFrame.class.getName();
/**
* Value for add/getComponent(): the online help display frame
*
* @see #getComponent( Object )
*/
public static final Object COMP_HELP = HelpFrame.class.getName();
/**
* Value for add/getComponent(): audio file header information
*
* @see #getComponent( Object )
*/
public static final Object COMP_AUDIOINFO = AudioFileInfoPalette.class.getName();
private final OSCRouterWrapper osc;
private static final String OSC_MAIN = "main";
private final ProcessingThread.Listener quitAfterSaveListener;
public final static boolean isMac = System.getProperty("os.name").contains("Mac OS");
public final static boolean isWindows = System.getProperty("os.name").contains("Windows");
public final static boolean isLinux = !(isMac || isWindows); // Well...
/**
* The arguments may contain the following options:
* <UL>
* <LI>-laf <screenName> <className> : set the default look-and-feel</LI>
* </UL>
*
* All other arguments not starting with a hyphen are considered to be paths to documents
* that will be opened after launch.
*/
public Main(String[] args) {
super(Main.class, APP_NAME);
final List<String> warnings;
final Preferences prefs = getUserPrefs();
final double prefsVersion;
final MainFrame mainFrame;
final OSCRoot oscServer;
final SuperColliderClient superCollider;
List<String> openDoc = null;
// ---- init prefs ----
oscServer = new OSCRoot(prefs.node(OSCRoot.DEFAULT_NODE));
prefsVersion = prefs.getDouble(PrefsUtil.KEY_VERSION, 0.0);
if (prefsVersion < APP_VERSION) {
warnings = PrefsUtil.createDefaults(prefs, prefsVersion);
} else {
warnings = null;
}
// ---- check commandline options ----
// lafName = prefs.get(PrefsUtil.KEY_LOOKANDFEEL, null);
String lafName = null;
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
if (args[i].equals("-laf")) {
if ((i + 2) < args.length) {
UIManager.installLookAndFeel(args[i + 1], args[i + 2]);
if (lafName == null) lafName = args[i + 2];
i += 2;
} else {
System.err.println("Option -laf requires two additional arguments (screen-name and class-name).");
System.exit(1);
}
} else {
System.err.println("Unknown option " + args[i]);
System.exit(1);
}
} else {
if (openDoc == null) openDoc = new ArrayList<String>();
openDoc.add(args[i]);
}
}
oscServer.checkExisting(openDoc);
// ---- init look-and-feel ----
try {
if (lafName == null) {
final String lafType = prefs.get(PrefsUtil.KEY_LAF_TYPE, null);
if (PrefsUtil.VALUE_LAF_TYPE_NATIVE.equals(lafType)) {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} else if (PrefsUtil.VALUE_LAF_TYPE_METAL.equals(lafType)) {
UIManager.setLookAndFeel(MetalLookAndFeel.class.getName());
} else {
final boolean isDark = PrefsUtil.VALUE_LAF_TYPE_SUBMIN_DARK.equals(lafType);
Submin.install(isDark);
}
} else {
UIManager.setLookAndFeel(lafName);
}
} catch (Exception e) {
System.err.println("Could not set look-and-feel: " + e.getClass().getSimpleName() + " - " + e.getMessage());
}
// JFrame.setDefaultLookAndFeelDecorated( true );
// ---- init infrastructure ----
// warning : sequence is crucial
// oscServer = new OSCRoot( prefs.node( OSCRoot.DEFAULT_NODE ), 0x4549 );
osc = new OSCRouterWrapper( oscServer, this );
final CacheManager cache = new PrefCacheManager( prefs.node( PrefCacheManager.DEFAULT_NODE ));
superCollider = new SuperColliderClient();
init();
// ---- listeners ----
quitAfterSaveListener = new ProcessingThread.Listener() {
public void processStarted( ProcessingThread.Event e ) { /* empty */ }
// if the saving was successfull, we will call closeAll again
public void processStopped(ProcessingThread.Event e) {
if (e.isDone()) {
quit();
}
}
};
try {
superCollider.init();
} catch (IOException e1) {
BasicWindowHandler.showErrorDialog(null, e1, "SuperColliderClient Initialization");
System.exit(1);
return;
}
// ---- component views ----
mainFrame = new MainFrame();
((BasicWindowHandler) getWindowHandler()).setDefaultBorrower( mainFrame );
final AppWindow ctrlRoom = new ControlRoomFrame();
final AppWindow observer = new ObserverPalette();
// means no preferences found, so
// do some more default initializations
// and display splash screen
if (prefsVersion == 0.0) {
ctrlRoom.setVisible(true);
observer.setVisible(true);
if (cache.getFolder().isDirectory()) {
cache.setActive(true);
}
new WelcomeScreen(this);
}
if (warnings != null) {
for (Object warning : warnings) {
System.err.println(warning);
}
}
oscServer.init();
if (prefs.node(PrefsUtil.NODE_AUDIO).getBoolean(PrefsUtil.KEY_AUTOBOOT, false)) {
superCollider.boot();
}
// de.sciss.gui.MultiStateButton.makeTestFrame( javax.swing.SwingConstants.CENTER, javax.swing.SwingConstants.CENTER );
if (openDoc != null) {
for (String anOpenDoc : openDoc) {
getMenuFactory().openDocument(new File(anOpenDoc));
}
}
}
protected BasicMenuFactory createMenuFactory() {
return new MenuFactory(this);
}
protected DocumentHandler createDocumentHandler() {
return new de.sciss.eisenkraut.session.DocumentHandler(this);
}
protected BasicWindowHandler createWindowHandler() {
return new BasicWindowHandler(this);
}
private boolean forcedQuit = false;
public synchronized void quit() {
final Flag confirmed = new Flag(false);
final ProcessingThread pt = getMenuFactory().closeAll(forcedQuit, confirmed);
if (pt != null) {
pt.addListener(quitAfterSaveListener);
((BasicDocument) pt.getClientArg("doc")).start(pt);
} else if (confirmed.isSet()) {
OSCRoot.getInstance().quit();
SuperColliderClient.getInstance().quit();
super.quit();
}
}
public void forceQuit() {
forcedQuit = true;
quit();
}
// private void lookAndFeelUpdate(String className) {
// if (className != null) {
// try {
// UIManager.setLookAndFeel(className);
// AppWindow.lookAndFeelUpdate();
// } catch (Exception e1) {
// GUIUtil.displayError(null, e1, null);
// }
// }
// }
/**
* java VM starting method. does some
* static initializations and then creates
* an instance of <code>Main</code>.
*
* @param args are not parsed.
*/
public static void main(final String args[]) {
// --- run the main application ---
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
EventQueue.invokeLater(new Runnable() {
public void run() {
new Main(args);
}
});
}
// ------------ Application interface ------------
public static String getMacOSCreator() {
return CREATOR;
}
public double getVersion() {
return APP_VERSION;
}
// ---------------- OSCRouter interface ----------------
public String oscGetPathComponent() {
return OSC_MAIN;
}
public void oscRoute(RoutedOSCMessage rom) {
osc.oscRoute(rom);
}
public void oscAddRouter(OSCRouter subRouter) {
osc.oscAddRouter(subRouter);
}
public void oscRemoveRouter(OSCRouter subRouter) {
osc.oscRemoveRouter(subRouter);
}
public void oscCmd_quit(RoutedOSCMessage rom) {
try {
if (rom.msg.getArgCount() > 1) {
if (((Number) rom.msg.getArg(1)).intValue() != 0) {
forceQuit();
return;
}
}
quit();
} catch (ClassCastException e1) {
OSCRoot.failedArgType(rom, 1);
}
}
public void oscCmd_createTempFile(RoutedOSCMessage rom) {
try {
final File f = IOUtil.createTempFile();
try {
rom.replyDone(1, new Object[]{f.getAbsolutePath()});
} catch (IOException e11) {
OSCRoot.failed(rom, e11);
}
} catch (IOException e1) {
OSCRoot.failed(rom, e1);
}
}
public Object oscQuery_version() {
return (float) getVersion();
}
}