Bug 467205 - [10.10] FileDialog/DirectoryDialog with SWT.SHEET misplaced
after slide-down animation

Replaced deprecated NSSavePanel and NSOpenPanel APIs with newer ones.

The new API NSSavePanel.beginSheetModalForWindow that is required to
show the Sheet, uses objective-c block for completion
handler. This call can't be made directly from Java, as Java doesn't
support the block syntax (^). Hence, it is called from a wrapper
function inside C code in os_custom.c. The wrapper function calls
beginSheetModalForWindow with the objective C block syntax. The
completion handler block is also implemented in os_custom.c which
callsback to the Java
functionFileDialog/DirectoryDialog._completionHandler(). 



Change-Id: I45dabdddeababd3ac9d9f2b63932508fd2634176
Signed-off-by: Lakshmi Shanmugam <lshanmug@in.ibm.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c
index 08fac00..398f0c9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_custom.c
@@ -238,3 +238,35 @@
 }
 #endif
 
+typedef void (*FunctionPointer)(jintLong result);
+typedef void (^ObjcBlock)(jintLong result);
+
+/*
+Method that takes a function pointer as input and returns a objective-c block
+which calls the function pointed to by the function pointer.
+*/
+ObjcBlock functionToBlock(FunctionPointer func) {
+    return [[^(jintLong result) {
+                 func(result);
+             } copy] autorelease];
+}
+
+/*
+Wrapper function which receives a function pointer from Java and calls NSSavePanel.beginSheetModalForWindow
+with objective-C block (with block syntax) as the last parameter.
+*/ 
+#ifndef NO_beginSheetModalForWindow
+JNIEXPORT jintLong JNICALL OS_NATIVE(beginSheetModalForWindow)
+	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jintLong arg2, FunctionPointer arg3)
+{
+	jintLong rc = 0;
+	
+	OS_NATIVE_ENTER(env, that, beginSheetModalForWindow_FUNC);
+	
+	rc = (jintLong)((jintLong (*)(jintLong, jintLong, jintLong, void (^)(jintLong)))objc_msgSend)(arg0, arg1, arg2, functionToBlock(arg3));
+	
+	OS_NATIVE_EXIT(env, that, beginSheetModalForWindow_FUNC);
+	return rc;
+}
+#endif
+
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c
index 985d265..bac2ebb 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.c
@@ -448,6 +448,7 @@
 	"UTTypeEqual",
 	"UnionRgn",
 	"_1_1BIG_1ENDIAN_1_1",
+	"beginSheetModalForWindow",
 	"call",
 	"class_1addIvar",
 	"class_1addMethod",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h
index 1d72006..3fcc56d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/library/os_stats.h
@@ -458,6 +458,7 @@
 	UTTypeEqual_FUNC,
 	UnionRgn_FUNC,
 	_1_1BIG_1ENDIAN_1_1_FUNC,
+	beginSheetModalForWindow_FUNC,
 	call_FUNC,
 	class_1addIvar_FUNC,
 	class_1addMethod_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/AppKitFull.bridgesupport.extras b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/AppKitFull.bridgesupport.extras
index 7869c28..db372d3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/AppKitFull.bridgesupport.extras
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/AppKitFull.bridgesupport.extras
@@ -181,6 +181,9 @@
 			<arg swt_gen="true"></arg>
 			<retval swt_gen="true"></retval>
 		</method>
+		<method selector="stopModal" swt_gen="true">
+			<retval swt_gen="true"></retval>
+		</method>
 		<method selector="terminate:" swt_gen="true">
 			<arg swt_gen="true"></arg>
 			<retval swt_gen="true"></retval>
@@ -2793,10 +2796,18 @@
 			<arg swt_gen="true"></arg>
 			<retval swt_gen="true"></retval>
 		</method>
+		<method selector="setDirectoryURL:" swt_gen="true">
+			<arg swt_gen="true"></arg>
+			<retval swt_gen="true"></retval>
+		</method>
 		<method selector="setMessage:" swt_gen="true">
 			<arg swt_gen="true"></arg>
 			<retval swt_gen="true"></retval>
 		</method>
+		<method selector="setNameFieldStringValue:" swt_gen="true">
+			<arg swt_gen="true"></arg>
+			<retval swt_gen="true"></retval>
+		</method>
 		<method selector="setTitle:" swt_gen="true">
 			<arg swt_gen="true"></arg>
 			<retval swt_gen="true"></retval>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSApplication.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSApplication.java
index bcfc7e7..6bd75b3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSApplication.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSApplication.java
@@ -161,6 +161,10 @@
 	OS.objc_msgSend(this.id, OS.sel_stop_, sender != null ? sender.id : 0);
 }
 
+public void stopModal() {
+	OS.objc_msgSend(this.id, OS.sel_stopModal);
+}
+
 public void terminate(id sender) {
 	OS.objc_msgSend(this.id, OS.sel_terminate_, sender != null ? sender.id : 0);
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSSavePanel.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSSavePanel.java
index 8b6b3d5..c590a29 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSSavePanel.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSSavePanel.java
@@ -62,10 +62,18 @@
 	OS.objc_msgSend(this.id, OS.sel_setDirectory_, path != null ? path.id : 0);
 }
 
+public void setDirectoryURL(NSURL directoryURL) {
+	OS.objc_msgSend(this.id, OS.sel_setDirectoryURL_, directoryURL != null ? directoryURL.id : 0);
+}
+
 public void setMessage(NSString message) {
 	OS.objc_msgSend(this.id, OS.sel_setMessage_, message != null ? message.id : 0);
 }
 
+public void setNameFieldStringValue(NSString nameFieldStringValue) {
+	OS.objc_msgSend(this.id, OS.sel_setNameFieldStringValue_, nameFieldStringValue != null ? nameFieldStringValue.id : 0);
+}
+
 public void setTitle(NSString title) {
 	OS.objc_msgSend(this.id, OS.sel_setTitle_, title != null ? title.id : 0);
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
index 94a6831..552019f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java
@@ -127,6 +127,8 @@
 	public static final long /*int*/ sel_setShouldExpandItem_ = sel_registerName("setShouldExpandItem:");
 	public static final long /*int*/ sel_setShouldScrollClipView_ = sel_registerName("setShouldScrollClipView:");
 
+	public static final long /*int*/ sel_beginSheetModalForWindow_completionHandler_ = sel_registerName("beginSheetModalForWindow:completionHandler:");
+	
 	/* These are not generated in order to avoid creating static methods on all classes */
 	public static final long /*int*/ sel_isSelectorExcludedFromWebScript_ = sel_registerName("isSelectorExcludedFromWebScript:");
 	public static final long /*int*/ sel_webScriptNameForSelector_ = sel_registerName("webScriptNameForSelector:");
@@ -181,6 +183,19 @@
 
 	public static final long /*int*/ class_NSToolbarView = objc_getClass("NSToolbarView");
 
+	/*
+	 * Wrapper function which will call NSSavePanel.beginSheetModalForWindow. This
+	 * implementation allows passing of objective-C block from Java to C code, and
+	 * receives a callback from the block to a Java function. Here, handler is a
+	 * the function pointer of the function that will be called by the objective-C
+	 * block.
+	 */
+	/** @method flags=no_gen*/
+	public static native void beginSheetModalForWindow(long id, long sel, long window, long handler);
+	public static void beginSheetModalForWindow(NSPanel id, NSWindow window, long handler) {
+		OS.beginSheetModalForWindow(id.id, OS.sel_beginSheetModalForWindow_completionHandler_, window != null ? window.id : 0, handler);
+	}
+
 /** JNI natives */
 
 /** @method flags=jni */
@@ -655,7 +670,6 @@
  */
 public static final native void objc_msgSend_stret(NSSize result, long /*int*/ id, long /*int*/ sel, NSSize arg0, long /*int*/ arg1, long /*int*/ arg2, long /*int*/ arg3, long /*int*/ arg4, long /*int*/ arg5);
 
-
 /** This section is auto generated */
 
 /** Custom callbacks */
@@ -1907,6 +1921,7 @@
 public static final long /*int*/ sel_setDestination_allowOverwrite_ = sel_registerName("setDestination:allowOverwrite:");
 public static final long /*int*/ sel_setDictionary_ = sel_registerName("setDictionary:");
 public static final long /*int*/ sel_setDirectory_ = sel_registerName("setDirectory:");
+public static final long /*int*/ sel_setDirectoryURL_ = sel_registerName("setDirectoryURL:");
 public static final long /*int*/ sel_setDisplayMode_ = sel_registerName("setDisplayMode:");
 public static final long /*int*/ sel_setDisplaysLinkToolTips_ = sel_registerName("setDisplaysLinkToolTips:");
 public static final long /*int*/ sel_setDocumentCursor_ = sel_registerName("setDocumentCursor:");
@@ -2009,6 +2024,7 @@
 public static final long /*int*/ sel_setMinimumIntegerDigits_ = sel_registerName("setMinimumIntegerDigits:");
 public static final long /*int*/ sel_setMiterLimit_ = sel_registerName("setMiterLimit:");
 public static final long /*int*/ sel_setMovable_ = sel_registerName("setMovable:");
+public static final long /*int*/ sel_setNameFieldStringValue_ = sel_registerName("setNameFieldStringValue:");
 public static final long /*int*/ sel_setNeedsDisplay_ = sel_registerName("setNeedsDisplay:");
 public static final long /*int*/ sel_setNeedsDisplayInRect_ = sel_registerName("setNeedsDisplayInRect:");
 public static final long /*int*/ sel_setNumberOfVisibleItems_ = sel_registerName("setNumberOfVisibleItems:");
@@ -2131,6 +2147,7 @@
 public static final long /*int*/ sel_stop_ = sel_registerName("stop:");
 public static final long /*int*/ sel_stopAnimation_ = sel_registerName("stopAnimation:");
 public static final long /*int*/ sel_stopLoading_ = sel_registerName("stopLoading:");
+public static final long /*int*/ sel_stopModal = sel_registerName("stopModal");
 public static final long /*int*/ sel_string = sel_registerName("string");
 public static final long /*int*/ sel_stringByAddingPercentEscapesUsingEncoding_ = sel_registerName("stringByAddingPercentEscapesUsingEncoding:");
 public static final long /*int*/ sel_stringByAppendingPathComponent_ = sel_registerName("stringByAppendingPathComponent:");
@@ -4400,4 +4417,5 @@
 public static final native void memmove(NSSize dest, long /*int*/ src, long /*int*/ size);
 
 /** This section is auto generated */
+
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java
index 002e202..989b9bd 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/DirectoryDialog.java
@@ -12,6 +12,7 @@
 
 
 import org.eclipse.swt.*;
+import org.eclipse.swt.internal.*;
 import org.eclipse.swt.internal.cocoa.*;
 
 
@@ -34,6 +35,9 @@
  * @noextend This class is not intended to be subclassed by clients.
  */
 public class DirectoryDialog extends Dialog {
+	Callback completion_handler_callback;
+	NSOpenPanel panel;
+	String directoryPath;
 	String message = "", filterPath = "";
 
 /**
@@ -85,6 +89,11 @@
 	checkSubclass ();
 }
 
+long _completionHandler (long result) {
+	handleResponse(result);
+	return result;
+}
+
 /**
  * Returns the path which the dialog will use to filter
  * the directories it shows.
@@ -108,6 +117,19 @@
 	return message;
 }
 
+void handleResponse (long response) {
+	if (parent != null && (style & SWT.SHEET) != 0) {
+		NSApplication.sharedApplication().stopModal();
+	}
+	Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
+	display.setModalDialog(null);
+	if (response  == OS.NSFileHandlingPanelOKButton) {
+		NSString filename = panel.filename();
+		directoryPath = filterPath = filename.getString();
+	}
+	releaseHandles();
+}
+
 /**
  * Makes the dialog visible and brings it to the front
  * of the display.
@@ -121,10 +143,9 @@
  * </ul>
  */
 public String open () {
-	String directoryPath = null;
-	NSOpenPanel panel = NSOpenPanel.openPanel();
+	directoryPath = null;
+	panel = NSOpenPanel.openPanel();
 
-	Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
 	/*
 	 * This line is intentionally commented. Don't show hidden files forcefully,
 	 * instead allow Directory dialog to use the system preference.
@@ -137,25 +158,35 @@
 	panel.setCanChooseFiles(false);
 	panel.setCanChooseDirectories(true);
 	panel.setTreatsFilePackagesAsDirectories(true);
-	NSApplication application = NSApplication.sharedApplication();
-	if (parent != null && (style & SWT.SHEET) != 0) {
-		application.beginSheet(panel, parent.view.window (), null, 0, 0);
-	}
-	display.setModalDialog(this, panel);
+
 	NSString dir = (filterPath != null && filterPath.length() > 0) ? NSString.stringWith(filterPath) : null;
-	long /*int*/ response = panel.runModalForDirectory(dir, null);
+	panel.setDirectoryURL(NSURL.fileURLWithPath(dir));
+
+	Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
+	display.setModalDialog(this, panel);
+
 	if (parent != null && (style & SWT.SHEET) != 0) {
-		application.endSheet(panel, 0);
+		completion_handler_callback = new Callback(this, "_completionHandler", 1);
+		long handler = completion_handler_callback.getAddress();
+		if (handler == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+		OS.beginSheetModalForWindow(panel, parent.view.window(), handler);
+		NSApplication.sharedApplication().runModalForWindow(parent.view.window());
+	} else {
+		long response = panel.runModal();
+		handleResponse(response);
 	}
-	display.setModalDialog(null);
-	if (response == OS.NSFileHandlingPanelOKButton) {
-		NSString filename = panel.filename();
-		directoryPath = filterPath = filename.getString();
-	}
+
 //	options.optionFlags = OS.kNavSupportPackages | OS.kNavAllowOpenPackages | OS.kNavAllowInvisibleFiles;
 	return directoryPath;
 }
 
+void releaseHandles () {
+	if (completion_handler_callback != null) {
+		completion_handler_callback.dispose();
+		completion_handler_callback = null;
+	}
+	panel = null;
+}
 
 /**
  * Sets the dialog's message, which is a description of
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java
index 0b563e7..01399ed 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/FileDialog.java
@@ -38,13 +38,20 @@
  * @noextend This class is not intended to be subclassed by clients.
  */
 public class FileDialog extends Dialog {
+	Callback callback_completion_handler;
+	Callback callback_overwrite_existing_file;
 	NSSavePanel panel;
 	NSPopUpButton popup;
 	String [] filterNames = new String [0];
 	String [] filterExtensions = new String [0];
 	String [] fileNames = new String[0];
 	String filterPath = "", fileName = "";
+	String fullPath;
+	SWTPanelDelegate delegate = null;
 	int filterIndex = -1;
+	long /*int*/ jniRef = 0;
+	long /*int*/ method = 0;
+	long /*int*/ methodImpl = 0;
 	boolean overwrite = false;
 	static final char EXTENSION_SEPARATOR = ';';
 
@@ -101,6 +108,15 @@
 	checkSubclass ();
 }
 
+long _completionHandler (long result) {
+	handleResponse(result);
+	return result;
+}
+
+long /*int*/ _overwriteExistingFileCheck (long /*int*/ id, long /*int*/ sel, long /*int*/ str) {
+	return 1;
+}
+
 /**
  * Returns the path of the first file that was
  * selected in the dialog relative to the filter path, or an
@@ -188,104 +204,19 @@
 	return overwrite;
 }
 
-/**
- * Makes the dialog visible and brings it to the front
- * of the display.
- *
- * @return a string describing the absolute path of the first selected file,
- *         or null if the dialog was cancelled or an error occurred
- *
- * @exception SWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
- * </ul>
- */
-public String open () {
-	String fullPath = null;
-	fileNames = new String [0];
-	long /*int*/ method = 0;
-	long /*int*/ methodImpl = 0;
-	Callback callback = null;
-	if ((style & SWT.SAVE) != 0) {
-		NSSavePanel savePanel = NSSavePanel.savePanel();
-		panel = savePanel;
-		if (!overwrite) {
-			callback = new Callback(this, "_overwriteExistingFileCheck", 3);
-			long /*int*/ proc = callback.getAddress();
-			if (proc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
-			method = OS.class_getInstanceMethod(OS.class_NSSavePanel, OS.sel_overwriteExistingFileCheck);
-			if (method != 0) methodImpl = OS.method_setImplementation(method, proc);
-		}
-	} else {
-		NSOpenPanel openPanel = NSOpenPanel.openPanel();
-		openPanel.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
-		panel = openPanel;
+void handleResponse (long response) {
+	if (parent != null && (style & SWT.SHEET) != 0) {
+		NSApplication.sharedApplication().stopModal();
 	}
-
 	Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
-	panel.setCanCreateDirectories(true);
-	/*
-	 * This line is intentionally commented. Don't show hidden files forcefully,
-	 * instead allow File dialog to use the system preference.
-	 */
-	//	OS.objc_msgSend(panel.id, OS.sel_setShowsHiddenFiles_, true);
-	long /*int*/ jniRef = 0;
-	SWTPanelDelegate delegate = null;
-	if (filterExtensions != null && filterExtensions.length != 0) {
-		delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
-		jniRef = OS.NewGlobalRef(this);
-		if (jniRef == 0) error(SWT.ERROR_NO_HANDLES);
-		OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
-		panel.setDelegate(delegate);
-		NSPopUpButton widget = (NSPopUpButton)new NSPopUpButton().alloc();
-		widget.initWithFrame(new NSRect(), false);
-		widget.setTarget(delegate);
-		widget.setAction(OS.sel_sendSelection_);
-		NSMenu menu = widget.menu();
-		menu.setAutoenablesItems(false);
-		for (int i = 0; i < filterExtensions.length; i++) {
-			String str = filterExtensions [i];
-			if (filterNames != null && filterNames.length > i) {
-				str = filterNames [i];
-			}
-			NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
-			nsItem.initWithTitle(NSString.stringWith(str), 0, NSString.string());
-			menu.addItem(nsItem);
-			nsItem.release();
-		}
-		widget.selectItemAtIndex(0 <= filterIndex && filterIndex < filterExtensions.length ? filterIndex : 0);
-		widget.sizeToFit();
-		panel.setAccessoryView(widget);
-		popup = widget;
-
-		setAllowedFileType(filterExtensions[0]);
-		panel.setAllowsOtherFileTypes(true);
-		panel.setTreatsFilePackagesAsDirectories(shouldTreatAppAsDirectory(filterExtensions[0]));
-	} else {
-		panel.setTreatsFilePackagesAsDirectories(false);
-	}
-	panel.setTitle(NSString.stringWith(title != null ? title : ""));
-	NSApplication application = NSApplication.sharedApplication();
-	if (parent != null && (style & SWT.SHEET) != 0) {
-		application.beginSheet(panel, parent.view.window (), null, 0, 0);
-	}
-	display.setModalDialog(this, panel);
-	NSString dir = (filterPath != null && filterPath.length() > 0) ? NSString.stringWith(filterPath) : null;
-	NSString file = (fileName != null && fileName.length() > 0) ? NSString.stringWith(fileName) : null;
-	long /*int*/ response = panel.runModalForDirectory(dir, file);
-	if (parent != null && (style & SWT.SHEET) != 0) {
-		application.endSheet(panel, 0);
-	}
 	display.setModalDialog(null);
-	if (!overwrite) {
-		if (method != 0) OS.method_setImplementation(method, methodImpl);
-		if (callback != null) callback.dispose();
-	}
+
 	if (popup != null) {
 		filterIndex = (int)/*64*/popup.indexOfSelectedItem();
 	} else {
 		filterIndex = -1;
 	}
+
 	if (response == OS.NSFileHandlingPanelOKButton) {
 		NSString filename = panel.filename();
 		if ((style & SWT.SAVE) != 0) {
@@ -320,22 +251,102 @@
 			}
 		}
 	}
-	if (popup != null) {
-		panel.setAccessoryView(null);
-		popup.release();
-		popup = null;
-	}
-	if (delegate != null) {
-		panel.setDelegate(null);
-		delegate.release();
-	}
-	if (jniRef != 0) OS.DeleteGlobalRef(jniRef);
-	panel = null;
-	return fullPath;
+	releaseHandles();
 }
 
-long /*int*/ _overwriteExistingFileCheck (long /*int*/ id, long /*int*/ sel, long /*int*/ str) {
-	return 1;
+/**
+ * Makes the dialog visible and brings it to the front
+ * of the display.
+ *
+ * @return a string describing the absolute path of the first selected file,
+ *         or null if the dialog was cancelled or an error occurred
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
+ * </ul>
+ */
+public String open () {
+	fullPath = null;
+	if ((style & SWT.SAVE) != 0) {
+		NSSavePanel savePanel = NSSavePanel.savePanel();
+		panel = savePanel;
+		if (!overwrite) {
+			callback_overwrite_existing_file = new Callback(this, "_overwriteExistingFileCheck", 3);
+			long /*int*/ proc = callback_overwrite_existing_file.getAddress();
+			if (proc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+			method = OS.class_getInstanceMethod(OS.class_NSSavePanel, OS.sel_overwriteExistingFileCheck);
+			if (method != 0) methodImpl = OS.method_setImplementation(method, proc);
+		}
+	} else {
+		NSOpenPanel openPanel = NSOpenPanel.openPanel();
+		openPanel.setAllowsMultipleSelection((style & SWT.MULTI) != 0);
+		panel = openPanel;
+	}
+
+	panel.setCanCreateDirectories(true);
+	/*
+	 * This line is intentionally commented. Don't show hidden files forcefully,
+	 * instead allow File dialog to use the system preference.
+	 */
+	//	OS.objc_msgSend(panel.id, OS.sel_setShowsHiddenFiles_, true);
+	jniRef = 0;
+	delegate = null;
+	if (filterExtensions != null && filterExtensions.length != 0) {
+		delegate = (SWTPanelDelegate)new SWTPanelDelegate().alloc().init();
+		jniRef = OS.NewGlobalRef(this);
+		if (jniRef == 0) error(SWT.ERROR_NO_HANDLES);
+		OS.object_setInstanceVariable(delegate.id, Display.SWT_OBJECT, jniRef);
+		panel.setDelegate(delegate);
+		NSPopUpButton widget = (NSPopUpButton)new NSPopUpButton().alloc();
+		widget.initWithFrame(new NSRect(), false);
+		widget.setTarget(delegate);
+		widget.setAction(OS.sel_sendSelection_);
+		NSMenu menu = widget.menu();
+		menu.setAutoenablesItems(false);
+		for (int i = 0; i < filterExtensions.length; i++) {
+			String str = filterExtensions [i];
+			if (filterNames != null && filterNames.length > i) {
+				str = filterNames [i];
+			}
+			NSMenuItem nsItem = (NSMenuItem)new NSMenuItem().alloc();
+			nsItem.initWithTitle(NSString.stringWith(str), 0, NSString.string());
+			menu.addItem(nsItem);
+			nsItem.release();
+		}
+		widget.selectItemAtIndex(0 <= filterIndex && filterIndex < filterExtensions.length ? filterIndex : 0);
+		widget.sizeToFit();
+		panel.setAccessoryView(widget);
+		popup = widget;
+
+		setAllowedFileType(filterExtensions[0]);
+		panel.setAllowsOtherFileTypes(true);
+		panel.setTreatsFilePackagesAsDirectories(shouldTreatAppAsDirectory(filterExtensions[0]));
+	} else {
+		panel.setTreatsFilePackagesAsDirectories(false);
+	}
+	panel.setTitle(NSString.stringWith(title != null ? title : ""));
+	if (filterPath != null && filterPath.length() > 0) {
+		NSString dir = NSString.stringWith(filterPath);
+		panel.setDirectoryURL(NSURL.fileURLWithPath(dir));
+	}
+	if (fileName != null && fileName.length() > 0) {
+		panel.setNameFieldStringValue(NSString.stringWith(fileName));
+	}
+
+	Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
+	display.setModalDialog(this, panel);
+	if (parent != null && (style & SWT.SHEET) != 0) {
+		callback_completion_handler = new Callback(this, "_completionHandler", 1);
+		long handler = callback_completion_handler.getAddress();
+		if (handler == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+		OS.beginSheetModalForWindow(panel, parent.view.window(), handler);
+		NSApplication.sharedApplication().runModalForWindow(parent.view.window());
+	} else {
+		long response = panel.runModal();
+		handleResponse(response);
+	}
+	return fullPath;
 }
 
 long /*int*/ panel_shouldShowFilename (long /*int*/ id, long /*int*/ sel, long /*int*/ arg0, long /*int*/ arg1) {
@@ -372,6 +383,31 @@
 	return 1;
 }
 
+void releaseHandles() {
+	if (!overwrite) {
+		if (method != 0) OS.method_setImplementation(method, methodImpl);
+		if (callback_overwrite_existing_file != null) callback_overwrite_existing_file.dispose();
+		callback_overwrite_existing_file = null;
+	}
+	if (callback_completion_handler != null) {
+		callback_completion_handler.dispose();
+		callback_completion_handler = null;
+	}
+	if (popup != null) {
+		panel.setAccessoryView(null);
+		popup.release();
+		popup = null;
+	}
+	if (delegate != null) {
+		panel.setDelegate(null);
+		delegate.release();
+		delegate = null;
+	}
+	if (jniRef != 0) OS.DeleteGlobalRef(jniRef);
+	jniRef = 0;
+	panel = null;
+}
+
 void sendSelection (long /*int*/ id, long /*int*/ sel, long /*int*/ arg) {
 	if (filterExtensions != null && filterExtensions.length > 0) {
 		String fileTypes = filterExtensions[(int)/*64*/popup.indexOfSelectedItem ()];