package org.korsakow.ide;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import javax.swing.undo.UndoManager;
import org.apache.log4j.Logger;
import org.dsrg.soenea.domain.MapperException;
import org.dsrg.soenea.service.Registry;
import org.korsakow.domain.interf.IProject;
import org.korsakow.domain.interf.IResource;
import org.korsakow.domain.mapper.input.ResourceInputMapper;
import org.korsakow.eawt.IApplication;
import org.korsakow.ide.controller.ApplicationListener;
import org.korsakow.ide.controller.ProjectEditAction;
import org.korsakow.ide.controller.ResourceEditAction;
import org.korsakow.ide.lang.LanguageBundle;
import org.korsakow.ide.resources.ResourceType;
import org.korsakow.ide.ui.ProjectExplorer;
import org.korsakow.ide.ui.ResourceEditor;
import org.korsakow.ide.ui.SplashPage;
import org.korsakow.ide.ui.components.keywordpool.KeywordPool;
import org.korsakow.ide.ui.components.linkpool.LinkPool;
import org.korsakow.ide.ui.components.snupool.SnuPool;
import org.korsakow.ide.ui.controller.CommonTaskScheduler;
import org.korsakow.ide.ui.controller.ProjectExplorerController;
import org.korsakow.ide.ui.controller.action.ExitAction;
import org.korsakow.ide.ui.controller.action.interf.EditInterfaceAction;
import org.korsakow.ide.ui.controller.action.media.EditImageAction;
import org.korsakow.ide.ui.controller.action.media.EditSoundAction;
import org.korsakow.ide.ui.controller.action.media.EditTextAction;
import org.korsakow.ide.ui.controller.action.media.EditVideoAction;
import org.korsakow.ide.ui.controller.action.snu.EditSnuAction;
import org.korsakow.ide.ui.dialogs.AlertDialog;
import org.korsakow.ide.ui.dialogs.EditingConflictDialog;
import org.korsakow.ide.ui.dialogs.ErrorDialog;
import org.korsakow.ide.ui.dialogs.MissingMediaDialog;
import org.korsakow.ide.ui.resourceexplorer.ResourceTreeTable;
import org.korsakow.ide.util.EventListenerWeakList;
import org.korsakow.ide.util.Platform;
import org.korsakow.ide.util.PreferencesManager;
import org.korsakow.ide.util.UIResourceManager;
import org.korsakow.ide.util.UIUtil;
import org.korsakow.ide.util.Util;
import org.korsakow.services.ErrorMailer;
public class Application
{
private static Application instance;
public static synchronized Application getInstance()
{
return instance;
}
/**
* Should call this somewhere at the beginning to handle the possible exception the first time its created.
* @return
* @throws Exception
*/
public static synchronized Application initializeInstance() throws Exception
{
return initializeInstance(new Application());
}
/**
* Used in testing.
* @param application
* @return
* @throws Exception
*/
public static synchronized Application initializeInstance(Application application) throws Exception
{
if (instance != null)
throw new IllegalStateException("already initialized. should call this only once at startup");
instance = application;
return instance;
}
public static synchronized void destroyInstance()
{
if (instance != null) {
instance.destroy();
}
instance = null;
}
private final Hashtable<Long, ResourceEditor> openEditors = new Hashtable<Long, ResourceEditor>();
private final Hashtable<ResourceEditor, Long> openEditors2 = new Hashtable<ResourceEditor, Long>();
private final Hashtable<ResourceType, ResourceEditAction> resourceEditActions = new Hashtable<ResourceType, ResourceEditAction>();
private ProjectExplorer projectExplorer;
private ProjectExplorerController projectExplorerController;
private SnuPool snuPool;
private KeywordPool keywordPool;
private LinkPool linkPool;
private ResourceTreeTable possiblePool;
private final List<ResourceEditor> mostRecentFocusedEditors = new ArrayList<ResourceEditor>();
private final CommonTaskScheduler commonTaskScheduler = new CommonTaskScheduler();
/**
* Application is global. This means any listeners on it would otherwise have application-lifetime!
* Hence the listeners are weak. IMHO AWT fucked up not having listeners be always weak, in any case, its
* much easier to forcibly remember a reference than to forget it.
*/
private final EventListenerWeakList eventListeners = new EventListenerWeakList();
private File saveFile = null;
private long saveVersion = -1;
private final IApplication platformApplication;
private final UndoManager undoManager;
private final WindowListener openEditorsListener = new WindowAdapter() {
@Override
public void windowActivated(WindowEvent event) {
ResourceEditor editor = (ResourceEditor)event.getWindow();
// dont double add, but also bump this one to the end
if (mostRecentFocusedEditors.contains(editor))
mostRecentFocusedEditors.remove(editor);
mostRecentFocusedEditors.add(editor);
Application.this.notifyApplicationWindowActivated(event);
}
@Override
public void windowClosed(WindowEvent event) {
ResourceEditor editor = (ResourceEditor)event.getSource();
if (openEditors2.containsKey(editor))
openEditors.remove(openEditors2.get(editor));
openEditors2.remove(editor);
mostRecentFocusedEditors.remove(editor);
editor.removeWindowListener(openEditorsListener); // not neceesary since they dispose on close?
System.gc(); // might help? especially with media resources?
Application.this.notifyApplicationWindowClosed(event);
}
};
protected Application() throws Exception
{
UIUtil.runUITaskNow(new Runnable() {
public void run() {
Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable exception) {
Application.getInstance().showUnhandledErrorDialog(LanguageBundle.getString("general.errors.uncaughtexception.title"), LanguageBundle.getString("general.errors.uncaughtexception.message"), exception);
}
});
}
});
String applicationClassName = "";
switch (Platform.getOS())
{
case MAC:
applicationClassName = Registry.getProperty("application_classname_osx");
break;
case WIN:
applicationClassName = Registry.getProperty("application_classname_windows");
break;
case NIX:
applicationClassName = Registry.getProperty("application_classname_linux");
break;
}
platformApplication = (IApplication)Class.forName(applicationClassName).newInstance();
UIUtil.setUpLAF();
resourceEditActions.put(ResourceType.SNU, new EditSnuAction());
resourceEditActions.put(ResourceType.VIDEO, new EditVideoAction());
resourceEditActions.put(ResourceType.IMAGE, new EditImageAction());
resourceEditActions.put(ResourceType.TEXT, new EditTextAction());
resourceEditActions.put(ResourceType.SOUND, new EditSoundAction());
resourceEditActions.put(ResourceType.INTERFACE, new EditInterfaceAction());
resourceEditActions.put(ResourceType.PROJECT, new ProjectEditAction());
undoManager = new UndoManager();
undoManager.setLimit(999);
UIManager.put("AbstractUndoableEdit.undoText", "");
UIManager.put("AbstractUndoableEdit.redoText", "");
}
/**
* May not return. // TODO: why? then why the return value?
* @return whether the application has / is going to shutdown
*/
public boolean shutdown()
{
try {
if (!ExitAction.checkForChangesAndPrompt())
return false;
} catch (MapperException e) {
Logger.getLogger(getClass()).error("", e);
return false;
}
if (!notifyWillShutdown())
return false;
notifyShutdown();
return true;
}
/**
* TOOD: refactor this, perhaps into the Platform class
* @return
*/
public static String getUserHome()
{
return System.getProperty("user.home");
}
/**
* TODO: refactor this, perhaps into the Platform class, or maybe into Application
* @return
*/
public static String getKorsakowHome()
{
return getUserHome() + File.separatorChar + ".korsakow";
}
public static String getLogfilename()
{
return getKorsakowHome() + File.separatorChar + "korsakow.log";
}
public static String getUUID()
{
String uuid = PreferencesManager.getVersionIndependentPreferences().get("uuid", null);
if (uuid == null) {
uuid = UUID.randomUUID().toString();
PreferencesManager.getVersionIndependentPreferences().put("uuid", uuid);
}
return uuid;
}
public void notifyProjectLoaded(IProject activeProject)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onProjectLoaded(activeProject);
}
public long getSaveVersion()
{
return saveVersion;
}
public void setSaveFile(File file, long version)
{
saveFile = file;
saveVersion = version;
}
public File getSaveFile()
{
return saveFile;
}
public void enqueueCommonTask(Runnable runnable)
{
commonTaskScheduler.enqueue(runnable);
}
public void startCommonTasks()
{
commonTaskScheduler.start();
}
public void stopCommonTasks()
{
commonTaskScheduler.stop();
}
public IApplication getPlatformApplication()
{
return platformApplication;
}
public void clearRegistry()
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onResourcesCleared();
}
public void registerDeleted(final IResource resource)
{
UIUtil.runUITaskLater(new Runnable() {
public void run() {
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onResourceDeleted(resource);
}
});
}
private class NotifyKeywordsChangedTask implements Runnable
{
public void run()
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onKeywordsChanged();
}
}
public void notifyApplicationWindowActivated(WindowEvent event)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onWindowActivated(event);
}
public void notifyApplicationWindowClosed(WindowEvent event)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onWindowClosed(event);
}
public void notifyKeywordsChanged()
{
commonTaskScheduler.enqueue(new NotifyKeywordsChangedTask());
}
public void notifyResourceAdded(IResource resource)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onResourceAdded(resource);
}
public void notifyResourceModified(IResource resource)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onResourceModified(resource);
}
public void notifyResourceDeleted(IResource resource)
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onResourceDeleted(resource);
}
public void notifyShutdown()
{
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
listener.onApplicationShutdown();
}
public boolean notifyWillShutdown()
{
boolean willShutdown = true;
for (ApplicationListener listener : eventListeners.getListeners(ApplicationListener.class))
willShutdown = willShutdown && listener.onApplicationWillShutdown();
return willShutdown;
}
public ResourceEditor createResourceEditor(IResource resource)
{
ResourceEditor editor = new ResourceEditor();
editor.setResizable(false);
if (resource != null) {
openEditors.put(resource.getId(), editor);
openEditors2.put(editor, resource.getId());
}
editor.addWindowListener(openEditorsListener);
// Dimension size = editor.getPreferredSize();
// size.width = Math.min(size.width, 500);
// size.height = Math.min(size.height, 500);
// editor.setSize(size);
return editor;
}
public ResourceEditor editSound(long id) throws Exception
{
return edit(ResourceType.SOUND, id);
}
public ResourceEditor editVideo(long id) throws Exception
{
return edit(ResourceType.VIDEO, id);
}
public ResourceEditor editNew(ResourceType type) throws Exception
{
return editNew(type, null);
}
public ResourceEditor editNew(ResourceType type, Long id) throws Exception
{
if (!resourceEditActions.containsKey(type)) {
showUnhandledErrorDialog("No editor", "There is no editor for resources of type: " + type.getDisplayString()); // actually should never happen
return null;
}
ResourceEditor editor = resourceEditActions.get(type).run(null);
if (id != null)
openEditors2.put(editor, id);
return editor;
}
public ResourceEditor edit(ResourceType type, long id) throws Exception
{
if (!resourceEditActions.containsKey(type)) {
showUnhandledErrorDialog("No editor", "There is no editor for resources of type: " + type.getDisplayString()); // actually should never happen
return null;
}
ResourceEditor editor = resourceEditActions.get(type).run(ResourceInputMapper.map(id));
return editor;
}
/**
*
* @return may be null
*/
public ResourceEditor getMostRecentFocusedEditor()
{
if (mostRecentFocusedEditors.isEmpty())
return null;
return mostRecentFocusedEditors.get(mostRecentFocusedEditors.size()-1);
}
public ResourceEditor getOpenEditor(IResource resource)
{
if (resource != null && openEditors.containsKey(resource.getId()))
return openEditors.get(resource.getId());
return null;
}
/**
* Returns the currently open editors in order of most recently focused
* @return
*/
public Collection<ResourceEditor> getOpenEditors()
{
return new ArrayList<ResourceEditor>(mostRecentFocusedEditors); // cast OK since the source is a list
}
/**
*
* @param editor
* @return TODO: could this ever return null?
* @throws MapperException
*/
public IResource getResourceForEditor(ResourceEditor editor) throws MapperException
{
if (openEditors2.containsKey(editor))
return ResourceInputMapper.map(openEditors2.get(editor));
else
return null;
}
public void setSnuPoolDialog(final JFrame dialog, final SnuPool pool)
{
snuPool = pool;
pool.putClientProperty("dialog", dialog);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent event) {
pool.putClientProperty("dialog", null);
if (pool == snuPool) {
snuPool = null;
}
}
});
}
public JFrame getSnuPoolDialog()
{
if (snuPool == null)
return null;
return (JFrame)snuPool.getClientProperty("dialog");
}
public SnuPool getSnuPool()
{
return snuPool;
}
public void setLinkPoolDialog(final JFrame dialog, final LinkPool pool)
{
linkPool = pool;
linkPool.putClientProperty("dialog", dialog);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent event) {
pool.putClientProperty("dialog", null);
if (pool == linkPool) {
linkPool = null;
}
}
});
}
public JFrame getLinkPoolDialog()
{
if (linkPool == null)
return null;
return (JFrame)linkPool.getClientProperty("dialog");
}
public LinkPool getLinkPool()
{
return linkPool;
}
public void setKeywordPoolDialog(final JFrame dialog, final KeywordPool pool)
{
keywordPool = pool;
keywordPool.putClientProperty("dialog", dialog);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent event) {
pool.putClientProperty("dialog", null);
if (pool == keywordPool) {
keywordPool = null;
}
}
});
}
public JFrame getKeywordPoolDialog()
{
if (keywordPool == null)
return null;
return (JFrame)keywordPool.getClientProperty("dialog");
}
public KeywordPool getKeywordPool()
{
return keywordPool;
}
public void setPossiblePoolDialog(final JFrame dialog, final ResourceTreeTable pool)
{
possiblePool = pool;
possiblePool.putClientProperty("dialog", dialog);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent event) {
pool.putClientProperty("dialog", null);
if (pool == possiblePool) {
possiblePool = null;
}
}
});
}
public JFrame getPossiblePoolDialog()
{
if (possiblePool == null)
return null;
return (JFrame)possiblePool.getClientProperty("dialog");
}
public ResourceTreeTable getPossiblePool()
{
return possiblePool;
}
public ProjectExplorer getProjectExplorer()
{
if (projectExplorer == null) {
projectExplorer = new ProjectExplorer();
projectExplorer.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent event) {
shutdown();
}
});
projectExplorerController = new ProjectExplorerController(projectExplorer);
}
return projectExplorer;
}
public ProjectExplorerController getProjectExplorerController()
{
return projectExplorerController;
}
public ProjectExplorer showProjectExplorer()
{
ProjectExplorer resourceExplorer = getProjectExplorer();
resourceExplorer.pack();
Dimension d = new Dimension(925, 600);
resourceExplorer.setSize(d);
UIUtil.constrainSizeToScreen(resourceExplorer);
return resourceExplorer;
}
public EditingConflictDialog showEditingConflictDialog()
{
return showEditingConflictDialog(getProjectExplorer());
}
public EditingConflictDialog showEditingConflictDialog(JFrame parent)
{
EditingConflictDialog dialog = new EditingConflictDialog(parent);
dialog.setTitle("Editing Conflict");
dialog.setModal(true);
dialog.setSize(new Dimension(320, 240));
UIUtil.centerOnFrame(dialog, parent);
return dialog;
}
public MissingMediaDialog showMissingMediaDialog()
{
return showMissingMediaDialog(getProjectExplorer());
}
public MissingMediaDialog showMissingMediaDialog(JFrame parent)
{
MissingMediaDialog dialog = new MissingMediaDialog(parent);
dialog.setTitle("Missing Media");
dialog.setModal(true);
dialog.setSize(new Dimension(320, 240));
UIUtil.centerOnFrame(dialog, parent);
return dialog;
}
public void showUnhandledErrorDialog(Throwable details)
{
showUnhandledErrorDialog(LanguageBundle.getString("general.errors.uncaughtexception.title"), details.getClass().getCanonicalName(), details);
}
public void showUnhandledErrorDialog(String title, Throwable details)
{
showUnhandledErrorDialog(title, details.getClass().getCanonicalName(), details);
}
public void showUnhandledErrorDialog(String title, String message, Throwable details)
{
showUnhandledErrorDialog(title, message, Util.getStackTraceString(details), details);
}
public void showUnhandledErrorDialog(String title, String message)
{
showUnhandledErrorDialog(title, message, "", null);
}
/**
* An error has occurred which we did not expect or did not know how to handle.
* The user is alerted and given the option to send us feedback.
* @param title
* @param message
* @param details
*/
public void showUnhandledErrorDialog(String title, String message, String details, Throwable cause)
{
Logger.getLogger(Application.class).error(message, cause);
//This is where I should insert the request as to whether or not to mail an error
try {
String lastExceptionUUID = PreferencesManager.getPreferences(Application.class).get("errorMailer.last", "");
String currentExceptionUUID = Util.getStackTraceUUID(cause);
if (!lastExceptionUUID.equals(currentExceptionUUID)) {
boolean sent = ErrorMailer.sendError(title, message, cause);
if (sent) {
PreferencesManager.getPreferences(Application.class).put("errorMailer.last", currentExceptionUUID);
PreferencesManager.getPreferences(Application.class).flush();
}
}
} catch (Exception e) {
e.printStackTrace();
details += "\n\nAnd an Exception while trying to mail the error.\n"+Util.getStackTraceString(e);
}
ErrorDialog dialog = details.length()>0?new ErrorDialog(message, details):new ErrorDialog(message);
JOptionPane.showMessageDialog(getProjectExplorer(), dialog, title, JOptionPane.ERROR_MESSAGE, UIResourceManager.getIcon(UIResourceManager.ICON_ERROR));
}
/**
* The error has been handled but we still alert the user. No mailback though.
* @param title
* @param message
* @param details
*/
public void showHandledErrorDialog(String title, String message, String details)
{
ErrorDialog dialog = details.length()>0?new ErrorDialog(message, details):new ErrorDialog(message);
JOptionPane.showMessageDialog(getProjectExplorer(), dialog, title, JOptionPane.ERROR_MESSAGE, UIResourceManager.getIcon(UIResourceManager.ICON_ERROR));
}
public void showHandledErrorDialog(String title, String message)
{
showHandledErrorDialog(title, message, "");
}
public void showAlertDialog(Component parent, String title, JComponent message)
{
AlertDialog dialog = new AlertDialog(message);
JOptionPane.showMessageDialog(parent, dialog, title, JOptionPane.INFORMATION_MESSAGE);
}
public void showAlertDialog(Component parent, String title, String message) {
showAlertDialog(parent, title, AlertDialog.createMessage(message));
}
public void showAlertDialog(String title, String message)
{
showAlertDialog(getProjectExplorer(), title, AlertDialog.createMessage(message));
}
public void showAlertDialog(String title, JComponent message)
{
showAlertDialog(getProjectExplorer(), title, message);
}
public void showOneTimeAlertDialog(String dialogId, Component parent, String title, String message) {
showOneTimeAlertDialog(dialogId, parent, title, AlertDialog.createMessage(message));
}
public void showOneTimeAlertDialog(String dialogId, Component parent, String title, JComponent message) {
if (!PreferencesManager.getPreferences(AlertDialog.class).node(dialogId).getBoolean("show", true))
return;
AlertDialog dialog = new AlertDialog(message);
dialog.setDontShowAgainVisible(true);
dialog.setDontShowAgain(false);
JOptionPane.showMessageDialog(parent, dialog, title, JOptionPane.INFORMATION_MESSAGE);
if (dialog.getDontShowAgain()) {
PreferencesManager.getPreferences(AlertDialog.class).node(dialogId).putBoolean("show", false);
}
}
public boolean showOKCancelDialog(String title, Object message)
{
return showOKCancelDialog(getProjectExplorer(), title, message);
}
public boolean showOKCancelDialog(Component parent, String title, Object message)
{
int choice = JOptionPane.showConfirmDialog(parent, message, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
return choice == JOptionPane.OK_OPTION;
}
public DialogOptions showFileOverwriteDialog(String title, String message)
{
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(new JLabel(message));
JCheckBox applyToAll = new JCheckBox();
JPanel applyPanel = new JPanel();
applyPanel.add(new JLabel("Apply to all"));
applyPanel.add(applyToAll);
panel.add(applyPanel);
int choice = JOptionPane.showConfirmDialog(getProjectExplorer(), panel, title, JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
DialogOptions options = new DialogOptions();
options.dialogResult = choice == JOptionPane.YES_OPTION;
options.applyToAll = applyToAll.isSelected();
return options;
}
public File showFileOpenDialog(Component parent, File defaultFile)
{
return showFileOpenDialog(parent, defaultFile.getParentFile(), defaultFile);
}
public File showFileOpenDialog(Component parent, File defaultDir, File defaultFile)
{
return showFileOpenDialog(parent, defaultDir, defaultFile, null);
}
public File showFileOpenDialog(Component parent, File defaultDir, File defaultFile, FilenameFilter filter)
{
FileDialog fileDialog = new FileDialog(getProjectExplorer());
if (defaultFile != null) {
if (defaultDir != null)
fileDialog.setDirectory(defaultDir.getPath());
fileDialog.setFile(defaultFile.getName());
}
if (filter != null)
fileDialog.setFilenameFilter(filter);
fileDialog.setMode(FileDialog.LOAD);
fileDialog.setVisible(true);
String filename = fileDialog.getFile();
return filename!=null?new File(fileDialog.getDirectory(), filename):null;
}
public File showFileSaveDialog(Component parent, File defaultFile)
{
FileDialog fileDialog = new FileDialog(getProjectExplorer());
if (defaultFile != null) {
fileDialog.setDirectory(defaultFile.getParent());
fileDialog.setFile(defaultFile.getName());
}
fileDialog.setMode(FileDialog.SAVE);
fileDialog.setVisible(true);
String filename = fileDialog.getFile();
return filename!=null?new File(fileDialog.getDirectory(), filename):null;
}
public File showDirOpenDialog(Component parent, File defaultDir)
{
if (Platform.isMacOS()) {
System.setProperty("apple.awt.fileDialogForDirectories", "true");
FileDialog dialog = null;
if (parent instanceof JFrame == false && parent instanceof JDialog == false) {
parent = ((JComponent)parent).getTopLevelAncestor();
}
if (parent instanceof JFrame)
dialog = new FileDialog((JFrame)parent);
else
dialog = new FileDialog((JDialog)parent);
if (defaultDir != null)
dialog.setDirectory(defaultDir.getAbsolutePath());
dialog.setVisible(true);
if (dialog.getDirectory() == null || dialog.getFile() == null)
return null;
File file = new File(dialog.getDirectory(), dialog.getFile());
System.setProperty("apple.awt.fileDialogForDirectories", "false");
return file;
} else {
JFileChooser chooser = new JFileChooser();
if (defaultDir != null)
chooser.setCurrentDirectory(defaultDir);
chooser.setDialogType(JFileChooser.OPEN_DIALOG);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.showOpenDialog(parent);
File file = chooser.getSelectedFile();
return file;
}
}
/**
*
* @param parent
* @param title
* @param choices
* @return the index into choices which was selected
*/
public int showRadioChoiceDialog(Component parent, String title, String[] choices)
{
ButtonGroup group = new ButtonGroup();
Box panel = Box.createVerticalBox();
Map<ButtonModel, Integer> map = new HashMap<ButtonModel, Integer>();
for (int i = 0; i < choices.length; ++i)
{
JRadioButton button = new JRadioButton(choices[i], i==0);
group.add(button);
panel.add(button);
map.put(button.getModel(), i);
}
JOptionPane.showMessageDialog(parent, panel, title, JOptionPane.PLAIN_MESSAGE);
Integer selection = map.get(group.getSelection());
if (selection == null)
selection = -1;
return selection;
}
public void showAboutDialog()
{
final JDialog splashDialog = new JDialog(getProjectExplorer());
splashDialog.setModal(true);
splashDialog.setResizable(false);
SplashPage page = new SplashPage();
splashDialog.add(page);
splashDialog.pack();
UIUtil.centerOnFrame(splashDialog, getProjectExplorer());
splashDialog.setVisible(true);
}
public void addWindowListener(WindowListener listener)
{
getProjectExplorer().addWindowListener(listener);
}
public void addApplicationListener(ApplicationListener listener)
{
eventListeners.add(ApplicationListener.class, listener);
}
private long busyCount = 0;
public void beginBusyOperation()
{
beginBusyOperation(getProjectExplorer());
}
/**
* Call before beginning a lengthy operation in the UI thread. The effect might for example
* be to set the cursor to the "busy" cursor (hourglass on windows).
*/
public void beginBusyOperation(Component target)
{
if (busyCount++ >= 0) {
target.setCursor(new Cursor(Cursor.WAIT_CURSOR));
}
}
public void endBusyOperation()
{
endBusyOperation(getProjectExplorer());
}
/**
* Call after completing a lengthy operation in the UI thread. If this is the last such operation
* the default cursor is restored.
*/
public void endBusyOperation(Component target)
{
if (--busyCount < 1) {
target.setCursor(null);
}
}
public void destroy()
{
commonTaskScheduler.stop();
}
public UndoManager getUndoManager()
{
return undoManager;
}
}