1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-31 18:41:20 +00:00

[macOS] Prefer user specified file extensions over OS preferred one.

This commit is contained in:
Pāvels Nadtočajevs
2025-12-08 18:36:44 +02:00
parent 14e840dd75
commit 0a6f8c2554
3 changed files with 32 additions and 5 deletions

View File

@@ -1060,7 +1060,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
Vector<String> files; Vector<String> files;
String url; String url;
url.append_utf8([[[panel URL] path] UTF8String]); url.append_utf8([[[panel URL] path] UTF8String]);
files.push_back(url); files.push_back([panel_delegate validateFilename:url]);
if (callback.is_valid()) { if (callback.is_valid()) {
if (p_options_in_cb) { if (p_options_in_cb) {
Variant v_result = true; Variant v_result = true;
@@ -1179,7 +1179,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
for (NSUInteger i = 0; i != [urls count]; ++i) { for (NSUInteger i = 0; i != [urls count]; ++i) {
String url; String url;
url.append_utf8([[[urls objectAtIndex:i] path] UTF8String]); url.append_utf8([[[urls objectAtIndex:i] path] UTF8String]);
files.push_back(url); files.push_back([panel_delegate validateFilename:url]);
} }
if (callback.is_valid()) { if (callback.is_valid()) {
if (p_options_in_cb) { if (p_options_in_cb) {

View File

@@ -41,6 +41,7 @@
@interface GodotOpenSaveDelegate : NSObject <NSOpenSavePanelDelegate> { @interface GodotOpenSaveDelegate : NSObject <NSOpenSavePanelDelegate> {
NSSavePanel *dialog; NSSavePanel *dialog;
NSMutableArray *allowed_types; NSMutableArray *allowed_types;
Vector<Vector<String>> preferred_types;
HashMap<int, String> ctr_ids; HashMap<int, String> ctr_ids;
Dictionary options; Dictionary options;
@@ -51,7 +52,7 @@
} }
- (void)makeAccessoryView:(NSSavePanel *)p_panel filters:(const Vector<String> &)p_filters options:(const TypedArray<Dictionary> &)p_options; - (void)makeAccessoryView:(NSSavePanel *)p_panel filters:(const Vector<String> &)p_filters options:(const TypedArray<Dictionary> &)p_options;
- (void)setFileTypes:(NSMutableArray *)p_allowed_types; - (void)setFileTypes:(NSMutableArray *)p_allowed_types pref:(const Vector<Vector<String>> &)p_preftypes;
- (void)popupOptionAction:(id)p_sender; - (void)popupOptionAction:(id)p_sender;
- (void)popupCheckAction:(id)p_sender; - (void)popupCheckAction:(id)p_sender;
- (void)popupFileAction:(id)p_sender; - (void)popupFileAction:(id)p_sender;
@@ -60,5 +61,6 @@
- (int)setDefaultInt:(const String &)p_name value:(int)p_value; - (int)setDefaultInt:(const String &)p_name value:(int)p_value;
- (int)setDefaultBool:(const String &)p_name value:(bool)p_value; - (int)setDefaultBool:(const String &)p_name value:(bool)p_value;
- (void)setRootPath:(const String &)p_root_path; - (void)setRootPath:(const String &)p_root_path;
- (String)validateFilename:(const String &)p_path;
@end @end

View File

@@ -103,6 +103,7 @@
} }
NSMutableArray *new_allowed_types = [[NSMutableArray alloc] init]; NSMutableArray *new_allowed_types = [[NSMutableArray alloc] init];
Vector<Vector<String>> pref_types;
bool has_type_popup = false; bool has_type_popup = false;
{ {
NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:RTR("Format").utf8().get_data()]]; NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:RTR("Format").utf8().get_data()]];
@@ -117,6 +118,7 @@
NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]; NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
for (int i = 0; i < p_filters.size(); i++) { for (int i = 0; i < p_filters.size(); i++) {
Vector<String> tokens = p_filters[i].split(";"); Vector<String> tokens = p_filters[i].split(";");
Vector<String> pref_type;
if (tokens.size() >= 1) { if (tokens.size() >= 1) {
String flt = tokens[0].strip_edges(); String flt = tokens[0].strip_edges();
String mime = (tokens.size() >= 3) ? tokens[2].strip_edges() : String(); String mime = (tokens.size() >= 3) ? tokens[2].strip_edges() : String();
@@ -135,9 +137,11 @@
} }
if (ut) { if (ut) {
[type_filters addObject:ut]; [type_filters addObject:ut];
pref_type.push_back(str.replace("*.", "").strip_edges());
} }
} else { } else {
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]]; [type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
pref_type.push_back(str.replace("*.", "").strip_edges());
} }
} }
} }
@@ -158,6 +162,7 @@
if ([type_filters count] > 0) { if ([type_filters count] > 0) {
NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : tokens[1].strip_edges()).utf8().get_data()]; NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : tokens[1].strip_edges()).utf8().get_data()];
[new_allowed_types addObject:type_filters]; [new_allowed_types addObject:type_filters];
pref_types.push_back(pref_type);
[popup addItemWithTitle:name_str]; [popup addItemWithTitle:name_str];
} }
} }
@@ -171,6 +176,7 @@
} }
} else if (p_filters.size() == 1) { } else if (p_filters.size() == 1) {
Vector<String> tokens = p_filters[0].split(";"); Vector<String> tokens = p_filters[0].split(";");
Vector<String> pref_type;
if (tokens.size() >= 1) { if (tokens.size() >= 1) {
String flt = tokens[0].strip_edges(); String flt = tokens[0].strip_edges();
String mime = (tokens.size() >= 3) ? tokens[2] : String(); String mime = (tokens.size() >= 3) ? tokens[2] : String();
@@ -189,9 +195,11 @@
} }
if (ut) { if (ut) {
[type_filters addObject:ut]; [type_filters addObject:ut];
pref_type.push_back(str.replace("*.", "").strip_edges());
} }
} else { } else {
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]]; [type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
pref_type.push_back(str.replace("*.", "").strip_edges());
} }
} }
} }
@@ -210,10 +218,11 @@
if ([type_filters count] > 0) { if ([type_filters count] > 0) {
[new_allowed_types addObject:type_filters]; [new_allowed_types addObject:type_filters];
pref_types.push_back(pref_type);
} }
} }
} }
[self setFileTypes:new_allowed_types]; [self setFileTypes:new_allowed_types pref:pref_types];
} }
[base_view addSubview:view]; [base_view addSubview:view];
@@ -278,8 +287,9 @@
return cid; return cid;
} }
- (void)setFileTypes:(NSMutableArray *)p_allowed_types { - (void)setFileTypes:(NSMutableArray *)p_allowed_types pref:(const Vector<Vector<String>> &)p_preftypes {
allowed_types = p_allowed_types; allowed_types = p_allowed_types;
preferred_types = p_preftypes;
} }
- (instancetype)initWithDialog:(NSSavePanel *)p_dialog { - (instancetype)initWithDialog:(NSSavePanel *)p_dialog {
@@ -346,6 +356,21 @@
root = p_root_path; root = p_root_path;
} }
- (String)validateFilename:(const String &)p_path {
if (@available(macOS 11, *)) {
if (allowed_types) {
NSMutableArray *type_filters = [allowed_types objectAtIndex:cur_index];
UTType *ut = [type_filters objectAtIndex:0];
String ext = String::utf8([[ut preferredFilenameExtension] UTF8String]);
Vector<String> pref_ext = preferred_types[cur_index];
if (!pref_ext.is_empty() && !pref_ext.has(ext) && p_path.has_extension(ext)) {
return p_path.get_basename() + "." + pref_ext[0];
}
}
}
return p_path;
}
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError *_Nullable *)outError { - (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError *_Nullable *)outError {
if (root.is_empty()) { if (root.is_empty()) {
return YES; return YES;