From 1e96bcb37d44a23eef553eca70a3380d53d44043 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 23 Jul 2020 13:43:25 +0300 Subject: [PATCH 1/2] [X11] Auto-append file extension for GTK-based file dialogs --- src/Avalonia.X11/NativeDialogs/Gtk.cs | 3 ++ .../NativeDialogs/GtkNativeFileDialogs.cs | 45 ++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs index 82cf3c934f..77e410162f 100644 --- a/src/Avalonia.X11/NativeDialogs/Gtk.cs +++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs @@ -204,6 +204,9 @@ namespace Avalonia.X11.NativeDialogs [DllImport(GtkName)] public static extern IntPtr gtk_file_chooser_add_filter(IntPtr chooser, IntPtr filter); + + [DllImport(GtkName)] + public static extern IntPtr gtk_file_chooser_get_filter(IntPtr chooser); [DllImport(GtkName)] public static extern void gtk_widget_realize(IntPtr gtkWidget); diff --git a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs index 287a541bc8..6cf6c6f35f 100644 --- a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs +++ b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs @@ -16,7 +16,7 @@ namespace Avalonia.X11.NativeDialogs { private Task _initialized; private unsafe Task ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action, - bool multiSelect, string initialFileName, IEnumerable filters) + bool multiSelect, string initialFileName, IEnumerable filters, string defaultExtension) { IntPtr dlg; using (var name = new Utf8Buffer(title)) @@ -35,11 +35,13 @@ namespace Avalonia.X11.NativeDialogs foreach (var d in disposables) d.Dispose(); disposables.Clear(); } - + + var filtersDic = new Dictionary(); if(filters != null) foreach (var f in filters) { var filter = gtk_file_filter_new(); + filtersDic[filter] = f; using (var b = new Utf8Buffer(f.Name)) gtk_file_filter_set_name(filter, b); @@ -74,6 +76,15 @@ namespace Avalonia.X11.NativeDialogs } g_slist_free(gs); result = resultList.ToArray(); + + // GTK doesn't auto-append the extension, so we need to do that manually + if (action == GtkFileChooserAction.Save) + { + var currentFilter = gtk_file_chooser_get_filter(dlg); + filtersDic.TryGetValue(currentFilter, out var selectedFilter); + for (var c = 0; c < result.Length; c++) + result[c] = NameWithExtension(result[c], defaultExtension, selectedFilter); + } } gtk_widget_hide(dlg); @@ -101,7 +112,30 @@ namespace Avalonia.X11.NativeDialogs gtk_window_present(dlg); return tcs.Task; } - + + string NameWithExtension(string path, string defaultExtension, FileDialogFilter filter) + { + var name = Path.GetFileName(path); + if (name != null && !name.Contains(".")) + { + if (filter?.Extensions?.Count > 0) + { + if (defaultExtension != null + && filter.Extensions.Contains(defaultExtension)) + return path + "." + defaultExtension.TrimStart('.'); + + var ext = filter.Extensions.FirstOrDefault(x => x != "*"); + if (ext != null) + return path + "." + ext.TrimStart('.'); + } + + if (defaultExtension != null) + path += "." + defaultExtension.TrimStart('.'); + } + + return path; + } + public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) { await EnsureInitialized(); @@ -113,7 +147,8 @@ namespace Avalonia.X11.NativeDialogs dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save, (dialog as OpenFileDialog)?.AllowMultiple ?? false, Path.Combine(string.IsNullOrEmpty(dialog.Directory) ? "" : dialog.Directory, - string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), dialog.Filters)); + string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), dialog.Filters, + (dialog as SaveFileDialog)?.DefaultExtension)); } public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) @@ -125,7 +160,7 @@ namespace Avalonia.X11.NativeDialogs return await await RunOnGlibThread(async () => { var res = await ShowDialog(dialog.Title, platformImpl, - GtkFileChooserAction.SelectFolder, false, dialog.Directory, null); + GtkFileChooserAction.SelectFolder, false, dialog.Directory, null, null); return res?.FirstOrDefault(); }); } From 4ccaf5752de9186a96c885ec46684c2a9c9e8c42 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 23 Jul 2020 16:18:04 +0200 Subject: [PATCH 2/2] Remove local value for MaxHeight. --- src/Avalonia.Themes.Default/TitleBar.xaml | 2 +- src/Avalonia.Themes.Fluent/TitleBar.xaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/TitleBar.xaml index 45798d3fa1..4dba5b4ba4 100644 --- a/src/Avalonia.Themes.Default/TitleBar.xaml +++ b/src/Avalonia.Themes.Default/TitleBar.xaml @@ -15,7 +15,7 @@ - + diff --git a/src/Avalonia.Themes.Fluent/TitleBar.xaml b/src/Avalonia.Themes.Fluent/TitleBar.xaml index 45798d3fa1..4dba5b4ba4 100644 --- a/src/Avalonia.Themes.Fluent/TitleBar.xaml +++ b/src/Avalonia.Themes.Fluent/TitleBar.xaml @@ -15,7 +15,7 @@ - +