Browse Source

Merge pull request #7618 from luthfiampas/gtk-file-dialog-directory-navigation

GTK File Chooser: Navigate to Initial Directory
Max Katz 3 years ago
parent
commit
5c922c2a56

+ 13 - 4
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -41,13 +41,17 @@ namespace ControlCatalog.Pages
 
             this.FindControl<Button>("OpenFile").Click += async delegate
             {
+                // Almost guaranteed to exist
+                var fullPath = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName;
+                var initialFileName = fullPath == null ? null : System.IO.Path.GetFileName(fullPath);
+                var initialDirectory = fullPath == null ? null : System.IO.Path.GetDirectoryName(fullPath);
+
                 var result = await new OpenFileDialog()
                 {
                     Title = "Open file",
                     Filters = GetFilters(),
-                    Directory = lastSelectedDirectory,
-                    // Almost guaranteed to exist
-                    InitialFileName = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName
+                    Directory = initialDirectory,
+                    InitialFileName = initialFileName
                 }.ShowAsync(GetWindow());
                 results.Items = result;
                 resultsVisible.IsVisible = result?.Any() == true;
@@ -83,7 +87,12 @@ namespace ControlCatalog.Pages
                     Title = "Select folder",
                     Directory = lastSelectedDirectory,
                 }.ShowAsync(GetWindow());
-                lastSelectedDirectory = result;
+
+                if (!string.IsNullOrEmpty(result))
+                {
+                    lastSelectedDirectory = result;
+                }
+
                 results.Items = new [] { result };
                 resultsVisible.IsVisible = result != null;
             };

+ 4 - 1
src/Avalonia.X11/NativeDialogs/Gtk.cs

@@ -195,7 +195,10 @@ namespace Avalonia.X11.NativeDialogs
 
         [DllImport(GtkName)]
         public static extern void gtk_file_chooser_set_current_name(IntPtr chooser, Utf8Buffer file);
-        
+
+        [DllImport(GtkName)]
+        public static extern void gtk_file_chooser_set_current_folder(IntPtr chooser, Utf8Buffer file);
+
         [DllImport(GtkName)]
         public static extern IntPtr gtk_file_filter_new();
         

+ 46 - 20
src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs

@@ -15,8 +15,9 @@ namespace Avalonia.X11.NativeDialogs
     class GtkSystemDialog : ISystemDialogImpl
     {
         private Task<bool> _initialized;
-        private unsafe  Task<string[]> ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action,
-            bool multiSelect, string initialFileName, IEnumerable<FileDialogFilter> filters, string defaultExtension, bool overwritePrompt)
+
+        private unsafe Task<string[]> ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action,
+            bool multiSelect, string initialDirectory, string initialFileName, IEnumerable<FileDialogFilter> filters, string defaultExtension, bool overwritePrompt)
         {
             IntPtr dlg;
             using (var name = new Utf8Buffer(title))
@@ -44,7 +45,7 @@ namespace Avalonia.X11.NativeDialogs
                     filtersDic[filter] = f;
                     using (var b = new Utf8Buffer(f.Name))
                         gtk_file_filter_set_name(filter, b);
-                    
+
                     foreach (var e in f.Extensions)
                         using (var b = new Utf8Buffer("*." + e))
                             gtk_file_filter_add_pattern(filter, b);
@@ -100,17 +101,32 @@ namespace Avalonia.X11.NativeDialogs
                 gtk_dialog_add_button(dlg, open, GtkResponseType.Accept);
             using (var open = new Utf8Buffer("Cancel"))
                 gtk_dialog_add_button(dlg, open, GtkResponseType.Cancel);
+
+            if (initialDirectory != null)
+            {
+                using var dir = new Utf8Buffer(initialDirectory);
+                gtk_file_chooser_set_current_folder(dlg, dir);
+            }
+
             if (initialFileName != null)
-                using (var fn = new Utf8Buffer(initialFileName))
+            {
+                // gtk_file_chooser_set_filename() expects full path
+                using var fn = action == GtkFileChooserAction.Open
+                    ? new Utf8Buffer(Path.Combine(initialDirectory ?? "", initialFileName))
+                    : new Utf8Buffer(initialFileName);
+
+                if (action == GtkFileChooserAction.Save)
                 {
-                    if (action == GtkFileChooserAction.Save)
-                        gtk_file_chooser_set_current_name(dlg, fn);
-                    else
-                        gtk_file_chooser_set_filename(dlg, fn);
+                    gtk_file_chooser_set_current_name(dlg, fn);
                 }
+                else
+                {
+                    gtk_file_chooser_set_filename(dlg, fn);
+                }
+            }
 
             gtk_file_chooser_set_do_overwrite_confirmation(dlg, overwritePrompt);
-            
+
             gtk_window_present(dlg);
             return tcs.Task;
         }
@@ -144,13 +160,15 @@ namespace Avalonia.X11.NativeDialogs
 
             var platformImpl = parent?.PlatformImpl;
 
-            return await await RunOnGlibThread(
-                () => ShowDialog(dialog.Title, platformImpl,
-                    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,
-                    (dialog as SaveFileDialog)?.DefaultExtension, (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false));
+            return await await RunOnGlibThread(() => ShowDialog(
+                dialog.Title, platformImpl,
+                dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
+                (dialog as OpenFileDialog)?.AllowMultiple ?? false,
+                dialog.Directory,
+                dialog.InitialFileName,
+                dialog.Filters,
+                (dialog as SaveFileDialog)?.DefaultExtension,
+                (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false));
         }
 
         public async Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent)
@@ -161,12 +179,20 @@ namespace Avalonia.X11.NativeDialogs
 
             return await await RunOnGlibThread(async () =>
             {
-                var res = await ShowDialog(dialog.Title, platformImpl,
-                    GtkFileChooserAction.SelectFolder, false, dialog.Directory, null, null, false);
+                var res = await ShowDialog(
+                    dialog.Title,
+                    platformImpl,GtkFileChooserAction.SelectFolder,
+                    false,
+                    dialog.Directory,
+                    null,
+                    null,
+                    null,
+                    false);
+
                 return res?.FirstOrDefault();
             });
         }
-        
+
         async Task EnsureInitialized()
         {
             if (_initialized == null) _initialized = StartGtk();
@@ -174,7 +200,7 @@ namespace Avalonia.X11.NativeDialogs
             if (!(await _initialized))
                 throw new Exception("Unable to initialize GTK on separate thread");
         }
-        
+
         void UpdateParent(IntPtr chooser, IWindowImpl parentWindow)
         {
             var xid = parentWindow.Handle.Handle;