Community
Participate
Working Groups
NSSavePanel does not have API to turn off the prompt that asks the user to confirm overwrite if the file to save already exists. This is apparently "inconsistent with Mac OS X behavior", however most other platforms let the application control whether or not to prompt before overwriting an existing file. In order to fix bug 4727, we have added FileDialog.setOverwrite(boolean). There does not seem to be any way to implement this new API on Cocoa except possibly to use a private method: (BOOL)_overwriteExistingFileCheck:(NSString *)filename Scott, do you know if this method is going to stick around a while? :)
I tried subclassing NSSavePanel and reimplementing _overwriteExistingFileCheck and found that we can prevent the prompt from appearing this way. Of course it's not API so there's no guarantee how long this will work, and we'd be breaking Apple's Human Interface Guidlines which explicitly state that users will get an application modal alert.
(In reply to comment #1) > Of course > it's not API so there's no guarantee how long this will work, and we'd be > breaking Apple's Human Interface Guidlines which explicitly state that users > will get an application modal alert. Overriding SPI is a dangerous game, but in this case I think the worst that would happen is that if the method went away it would just not work instead of crashing. You're probably okay until there's a pure-Cocoa equivalent of kNavDontConfirmReplacement, which is how this would be implemented in Carbon. I would file a bug report with Apple asking for an equivalent Cocoa API.
Scott, go ahead and file it. In the meantime, my vote is to subclass and override.
Filed Radar 6250996 for completeness. I'm expecting it to be returned as a duplicate.
fixed > 20090206
This still reproduces for me. I don't have an easy repro case handy, but I noticed it when attempting to verify the patch I contributed for bug 276162: My patch works on Windows and on SWT-Carbon, but does not work on SWT-Cocoa. When I debugged it, I saw that the SWT-Cocoa version of FileDialog does have code to put in a callback if setOverwrite(true) was called, but the callback doesn't actually do anything: int /*long*/ _overwriteExistingFileCheck(int /*long*/ id, int /*long*/ sel, int /*long*/ str) { return 1; } I suspect there is probably some code that's supposed to go in there to check for an existing file. Another possible way to verify this, although I don't have time to try it myself, is to start with the SWT Snippet for FileDialog, add a call to dialog.setOverwrite(true) before the call to dialog.open(), and see what happens; I bet it won't ask for confirmation on SWT-Cocoa, but will on Carbon and on Windows.
This works for me. The _overwriteExistingFileCheck callback will only get called if setOverwrite(true) was called before the FileDialog was opened. In open this code replaces the default method implementation with our function that always returns 1 (true). if (overwrite) { callback = new Callback(this, "_overwriteExistingFileCheck", 3); int /*long*/ 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); }
oh... we have it backwards. setOverwrite(true) means prompt, not over write.
Created attachment 135974 [details] Patch
Created attachment 136070 [details] minimal patch
The patch is good. I tested with the following snippet (in case it's useful for other reviewers... ;) import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.events.*; public class FileDialogOverwritePromptTest { public static void main(String[] args) { Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new GridLayout()); final Button prompt = new Button(shell, SWT.CHECK); prompt.setText("Overwrite Prompt"); Button button = new Button(shell, SWT.PUSH); button.setText("Open FileDialog"); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { FileDialog dialog = new FileDialog(shell, SWT.SAVE); boolean p = prompt.getSelection(); System.out.println("Setting overwrite prompt to " + p); dialog.setOverwrite(p); System.out.println(dialog.open()); System.out.println("Overwrite prompt was " + dialog.getOverwrite()); }; }); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } } }
fixed > 20090515