Bug 567754 - File dialog does not change file name when switching file type As of macOS 10.15, all apps have the sandbox versions of the Open/Save panels even if they are not sandboxed. This means you can't setNameFieldStringValue; an unsecure app might change the filename when the user was not expecting it. Use setAllowedFileType for NSSavePanel, instead of trying to explicitly append the selected extension. The side effect of using setAllowedFileType is that if a multi-part extension (such as tar.gz) is selected in Save Dialog's extension pop-up, only the last part (gz) is considered as the extension. This is because, Mac doesn't support multi-part extensions, it only considers the last part of the extension. Change-Id: Ife16e33b8f0d75b384d46c2db8d2effd4ffd43b9
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/FoundationFull.bridgesupport.extras b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/FoundationFull.bridgesupport.extras index ef199a7..ad2cba6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/FoundationFull.bridgesupport.extras +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/FoundationFull.bridgesupport.extras
@@ -391,6 +391,11 @@ <arg swt_gen="true"></arg> <retval swt_gen="true"></retval> </method> + <method selector="insertObject:atIndex:" swt_gen="true"> + <arg swt_gen="true"></arg> + <arg swt_gen="true"></arg> + <retval swt_gen="true"></retval> + </method> <method selector="removeLastObject" swt_gen="true"> <retval swt_gen="true"></retval> </method>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSMutableArray.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSMutableArray.java index 1d7d383..86e8250 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSMutableArray.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/NSMutableArray.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2021 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -45,6 +45,10 @@ return result == this.id ? this : (result != 0 ? new NSMutableArray(result) : null); } +public void insertObject(id anObject, long index) { + OS.objc_msgSend(this.id, OS.sel_insertObject_atIndex_, anObject != null ? anObject.id : 0, index); +} + public void removeLastObject() { OS.objc_msgSend(this.id, OS.sel_removeLastObject); }
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 dd5f6c3..dfa3607 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
@@ -1281,6 +1281,7 @@ public static final long sel_insertItem_atIndex_ = Selector.sel_insertItem_atIndex_.value; public static final long sel_insertItemWithItemIdentifier_atIndex_ = Selector.sel_insertItemWithItemIdentifier_atIndex_.value; public static final long sel_insertItemWithObjectValue_atIndex_ = Selector.sel_insertItemWithObjectValue_atIndex_.value; +public static final long sel_insertObject_atIndex_ = Selector.sel_insertObject_atIndex_.value; public static final long sel_insertTabViewItem_atIndex_ = Selector.sel_insertTabViewItem_atIndex_.value; public static final long sel_insertText_ = Selector.sel_insertText_.value; public static final long sel_intValue = Selector.sel_intValue.value;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java index c34b0ed..dc3482f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/Selector.java
@@ -554,6 +554,7 @@ , sel_insertItem_atIndex_("insertItem:atIndex:") , sel_insertItemWithItemIdentifier_atIndex_("insertItemWithItemIdentifier:atIndex:") , sel_insertItemWithObjectValue_atIndex_("insertItemWithObjectValue:atIndex:") + , sel_insertObject_atIndex_("insertObject:atIndex:") , sel_insertTabViewItem_atIndex_("insertTabViewItem:atIndex:") , sel_insertText_("insertText:") , sel_intValue("intValue")
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 d1ab69d..667e8b8 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
@@ -57,6 +57,7 @@ long methodImpl = 0; boolean overwrite = false; static final char EXTENSION_SEPARATOR = ';'; + private String selectedExtension; /** * Constructs a new instance of this class given only its parent. @@ -121,37 +122,15 @@ } /** - * Appends the extension to the filename, only if the filename has no extension already. - */ -private NSString appendExtension (NSString filename, String extension) { - if (filename != null && extension != null) { - NSString ext = filename.pathExtension(); - if (ext == null || ext.length() == 0) { - filename = filename.stringByAppendingPathExtension(NSString.stringWith(extension)); - } - } - return filename; -} - -/** * Appends the extension selected in the filter pop-up to the filename, * only if the filename has no extension already. */ private NSString appendSelectedExtension (NSString filename) { String extension = getSelectedExtension(); - return appendExtension(filename, extension); -} - -/** - * Returns the filename without the extension from the full file path. - */ -private NSString fileNameWithoutExtension (NSString filePath) { - NSString filename = filePath.lastPathComponent(); - if (filename != null) { + if (filename != null && extension != null) { NSString ext = filename.pathExtension(); - while (ext != null && ext.length() > 0) { - filename = filename.stringByDeletingPathExtension(); - ext = filename.pathExtension(); + if (ext == null || ext.length() == 0) { + filename = filename.stringByAppendingPathExtension(NSString.stringWith(extension)); } } return filename; @@ -250,26 +229,44 @@ * Returns null if no extension is selected or if the selected filter is * or *.* */ private String getSelectedExtension () { - if (popup != null) { - filterIndex = (int)popup.indexOfSelectedItem(); - } else { - filterIndex = -1; - } + return selectedExtension; +} + +private NSMutableArray getSelectedExtensions () { + int filterIndex = popup != null ? (int)popup.indexOfSelectedItem() : -1; if (filterExtensions != null && filterExtensions.length != 0) { if (0 <= filterIndex && filterIndex < filterExtensions.length) { String exts = filterExtensions [filterIndex]; - int length = exts.length (); int index = exts.indexOf (EXTENSION_SEPARATOR); - if (index == -1) index = length; - String filter = exts.substring (0, index).trim (); - if (!filter.equals ("*") && !filter.equals ("*.*")) { - if (filter.startsWith ("*.")) { - filter = filter.substring (2); - } else if (filter.startsWith (".")) { - filter = filter.substring (1); + String[] extensions = index != -1 ? exts.split(";") : new String[] {exts}; + + int length = extensions.length; + NSMutableArray allowedFileTypes = NSMutableArray.arrayWithCapacity(length); + for (int j = length - 1; j >= 0; j--) { + String ext = extensions[j]; + String filter = ext.trim (); + if (!filter.equals ("*") && !filter.equals ("*.*")) { + if (filter.startsWith ("*.")) { + filter = filter.substring (2); + } else if (filter.startsWith (".")) { + filter = filter.substring (1); + } + selectedExtension = filter; + /* + * Mac doesn't support multi-part extensions, use only the last part as + * extension in this case. + */ + int i = filter.lastIndexOf("."); + if (i != -1 && ((i + 1) < filter.length())) { + filter = filter.substring(i + 1); + } + allowedFileTypes.insertObject(NSString.stringWith(filter), 0); + } else { + selectedExtension = null; + return null; } - return filter; } + return allowedFileTypes; } } return null; @@ -282,6 +279,8 @@ Display display = parent != null ? parent.getDisplay() : Display.getCurrent(); display.setModalDialog(null); + filterIndex = popup != null ? (int)popup.indexOfSelectedItem() : -1; + if (response == OS.NSFileHandlingPanelOKButton) { NSString filename = panel.filename(); if ((style & SWT.SAVE) != 0) { @@ -353,6 +352,14 @@ panel = openPanel; } panel.setCanCreateDirectories(true); + 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)); + } /* * This line is intentionally commented. Don't show hidden files forcefully, * instead allow File dialog to use the system preference. @@ -388,23 +395,14 @@ panel.setAccessoryView(widget); popup = widget; panel.setTreatsFilePackagesAsDirectories(shouldTreatAppAsDirectory(filterExtensions[selectionIndex])); + if ((style & SWT.SAVE) != 0) { + NSArray extensions = getSelectedExtensions(); + if (extensions != null) panel.setAllowedFileTypes(extensions); + panel.setAllowsOtherFileTypes(true); + } } 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)); - } - NSString nameFieldStringValue = panel.nameFieldStringValue(); - if (nameFieldStringValue != null) { - nameFieldStringValue = appendSelectedExtension(nameFieldStringValue); - panel.setNameFieldStringValue(nameFieldStringValue); - } - Display display = parent != null ? parent.getDisplay() : Display.getCurrent(); display.setModalDialog(this, panel); if (parent != null && (style & SWT.SHEET) != 0) { @@ -509,17 +507,12 @@ String fileTypes = filterExtensions[(int)popup.indexOfSelectedItem ()]; panel.setTreatsFilePackagesAsDirectories (shouldTreatAppAsDirectory (fileTypes)); - /* Update the name field in the dialog with the correct extension */ + /* + * Update the allowed file types in the dialog. If extension is not hidden, this + * updates the extension in the name field. + */ if ((style & SWT.SAVE) != 0) { - String selectedExt = getSelectedExtension(); - if (selectedExt != null) { - NSString filePath = panel.filename(); - if (filePath != null) { - NSString filenameNoExt = fileNameWithoutExtension(filePath); - NSString filename = appendExtension(filenameNoExt, selectedExt); - if (filename != null) panel.setNameFieldStringValue(filename); - } - } + panel.setAllowedFileTypes(getSelectedExtensions()); return; } }