package tk.amberide;
import tk.amberide.ide.data.io.LoggedOutputStream;
import tk.amberide.ide.os.OS;
import tk.amberide.ide.data.res.xml.XMLResourceManager;
import tk.amberide.ide.data.Workspace;
import tk.amberide.ide.data.state.IStateManager;
import tk.amberide.ide.data.state.LazyState;
import tk.amberide.ide.data.state.Scope;
import tk.amberide.ide.data.state.node.IState;
import tk.amberide.ide.data.state.node.SimpleState;
import tk.amberide.ide.data.state.xml.XMLStateManager;
import tk.amberide.ide.gui.AmberUIManager;
import tk.amberide.ide.gui.FileViewerPanel;
import tk.amberide.ide.gui.editor.map.MapEditorPanel;
import tk.amberide.ide.gui.editor.text.ScriptEditorPanel;
import tk.amberide.ide.gui.misc.ErrorHandler;
import tk.amberide.ide.gui.misc.FileSystemIcon;
import tk.amberide.ide.gui.misc.TipOfTheDay;
import tk.amberide.ide.gui.viewer.AudioViewerPanel;
import tk.amberide.ide.gui.viewer.ImageViewerPanel;
import tk.amberide.ide.swing.Dialogs;
import tk.amberide.ide.swing.UIUtil;
import tk.amberide.ide.tool.ToolDefinition;
import java.awt.EventQueue;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
/**
* @author Tudor
*/
public class Amber {
private static IDE main;
private static XMLResourceManager resources;
private static IStateManager states = new XMLStateManager();
private static Workspace workspace;
private static File root = new File(System.getProperty("user.home") + File.separatorChar + ".amber");
static {
if (!root.exists()) {
root.mkdirs();
}
}
/**
* Main method: entry point to Amber. Should not be called directly.
*
* @param args arguments to hint options to Amber
*/
public static void main(final String[] args) throws FileNotFoundException {
try {
OS.loadNativeLibraries();
Storage.init();
//setupLogging();
UIUtil.makeNative();
AmberUIManager.setup();
try {
ErrorHandler.init();
} catch (Exception e) {
}
ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Shutting down...");
try {
if (states != null) {
states.emitStates();
}
if (resources != null) {
resources.emitResources();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
if (args.length == 1) {
initializeProject(new File(args[0]));
}
states.registerMacro("${GLOBAL.DIR}", root.getAbsolutePath());
loadStates(Scope.GLOBAL);
setupFileIcons();
setupFileViewers();
Settings.load();
EventQueue.invokeLater(new Runnable() {
public void run() {
main = new IDE();
try {
restoreLastWorkspace();
} catch (Exception ex) {
ex.printStackTrace();
}
main.setVisible(true);
showTipOfTheDay();
states.registerStateOwner(Amber.class);
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
@LazyState(scope = Scope.GLOBAL, name = "LastProjectDirectory")
protected static String saveLastProject() {
return workspace != null ? workspace.getRootDirectory().getAbsolutePath() : null;
}
private static void setupFileViewers() {
FileViewerPanel.setDefaultPanel(ScriptEditorPanel.class);
FileViewerPanel.registerPanel(MapEditorPanel.class, "m");
FileViewerPanel.registerPanel(ImageViewerPanel.class, "jpg", "jpeg", "png", "gif", "bmp");
FileViewerPanel.registerPanel(AudioViewerPanel.class, "wav", "midi", "mid", "aiff", "ogg");
}
private static void setupFileIcons() {
FileSystemIcon.setIcon("m", new ImageIcon(ClassLoader.getSystemResource("icon/General.Map.png")));
FileSystemIcon.setIcon("rb", new ImageIcon(ClassLoader.getSystemResource("icon/General.Script.png")));
}
private static void restoreLastWorkspace() throws Exception {
IState lastProject = states.getState(Scope.GLOBAL, "LastProjectDirectory");
if (workspace == null && lastProject != null && lastProject.get() != null) {
File root = new File((String) lastProject.get());
System.out.println("Loaded project " + root);
if (root.exists()) {
openWorkspace(root);
}
}
}
private static void openWorkspace(File root) throws Exception {
workspace = new Workspace(root);
resources = new XMLResourceManager(workspace);
resources.loadResources();
root.mkdirs();
states.registerMacro("${PROJECT.DIR}", workspace.getDataDirectory().getAbsolutePath());
states.clearStates(Scope.PROJECT);
states.loadStates(Scope.PROJECT);
main.loadProject(workspace);
main.setTitle(String.format("Amber IDE (%s)", root.getAbsolutePath()));
Storage.recentProjects.put(workspace.getRootDirectory().getAbsolutePath(), new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
main.validate();
}
private static void setupLogging() throws IOException {
File log = new File("amber.log");
if (!log.exists()) {
log.createNewFile();
}
LoggedOutputStream logger = new LoggedOutputStream(log);
System.setOut(logger);
System.setErr(logger);
}
private static void loadStates(int scope) {
try {
states.loadStates(scope);
} catch (Exception e) {
e.printStackTrace();
Dialogs.errorDialog()
.setTitle("Failed to load previous state")
.setMessage("Something went wrong while restoring project state: " + e)
.show();
}
}
private static void showTipOfTheDay() {
IState tips = states.getState(Scope.GLOBAL, "ShowTipOfTheDay");
if (tips == null) {
tips = new SimpleState("ShowTipOfTheDay", true);
states.addState(Scope.GLOBAL, tips);
}
if ((Boolean) tips.get()) {
((SimpleState) tips).set(TipOfTheDay.showTipOfTheDay());
}
}
/**
* Initializes a new Amber project in the specified root folder, and opens
* it in the UI.
*
* @param root the directory that the project should be created in
*/
public static void initializeProject(File root) {
if (workspace != null) {
if (Dialogs.confirmDialog()
.setTitle("Opening project...")
.setMessage("The project can either be opened in this window, or in a new window.\n"
+ "Where would you like to open the project?")
.setOptionType(JOptionPane.YES_NO_CANCEL_OPTION)
.setMessageType(JOptionPane.QUESTION_MESSAGE)
.setOptions("This window", "New window", "Cancel").show() == JOptionPane.NO_OPTION) {
try {
OS.newInstance(Amber.class, root.getAbsolutePath());
return;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
try {
openWorkspace(root);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Fetches the current project ResourceManager
*
* @return the resource manager currently in use
*/
public static XMLResourceManager getResourceManager() {
return resources;
}
/**
* Fetches the Workspace of the current project
*
* @return the Workspace object
*/
public static Workspace getWorkspace() {
return workspace;
}
/**
* Opens a file in the editor panel. Type lookup is done by file extension.
*
* @param file the file to be opened
*/
public static void openFileTab(File file) {
main.openFile(file);
}
public static void openToolTab(ToolDefinition tool) {
main.addToolTab(tool);
}
/**
* Gets the main JFrame which hosts the current Amber IDE process
*
* @return the IDE JFrame
*/
public static IDE getUI() {
return main;
}
public static IStateManager getStateManager() {
return states;
}
}