From 02b9a0bb9735350812f6632c45c05279e9560e7d Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Wed, 14 Sep 2022 12:49:38 -0700 Subject: [PATCH] Make FileDialog.FileName consistent across platforms Mac: Fix setting FileName to null Mac/Gtk: Remember set value before/after dialog is shown Added test to ensure things work as expected --- src/Eto.Gtk/Forms/GtkFileDialog.cs | 28 ++++++++-- ...FileDialog.cs => OpenFileDialogHandler.cs} | 26 ++++++++- ...FileDialog.cs => SaveFileDialogHandler.cs} | 0 src/Eto.Mac/Forms/MacFileDialog.cs | 28 ++++------ ...FileDialog.cs => OpenFileDialogHandler.cs} | 0 src/Eto.Mac/Forms/SaveFileDialogHandler.cs | 19 +++++-- ...FileDialog.cs => OpenFileDialogHandler.cs} | 0 ...FileDialog.cs => SaveFileDialogHandler.cs} | 0 .../UnitTests/Forms/FileDialogTests.cs | 55 +++++++++++++++++++ 9 files changed, 127 insertions(+), 29 deletions(-) rename src/Eto.Gtk/Forms/{OpenFileDialog.cs => OpenFileDialogHandler.cs} (51%) rename src/Eto.Gtk/Forms/{SaveFileDialog.cs => SaveFileDialogHandler.cs} (100%) rename src/Eto.Mac/Forms/{OpenFileDialog.cs => OpenFileDialogHandler.cs} (100%) rename src/Eto.WinForms/Forms/{OpenFileDialog.cs => OpenFileDialogHandler.cs} (100%) rename src/Eto.WinForms/Forms/{SaveFileDialog.cs => SaveFileDialogHandler.cs} (100%) create mode 100644 test/Eto.Test/UnitTests/Forms/FileDialogTests.cs diff --git a/src/Eto.Gtk/Forms/GtkFileDialog.cs b/src/Eto.Gtk/Forms/GtkFileDialog.cs index a9265ff92b..f96e344798 100644 --- a/src/Eto.Gtk/Forms/GtkFileDialog.cs +++ b/src/Eto.Gtk/Forms/GtkFileDialog.cs @@ -10,14 +10,30 @@ public abstract class GtkFileDialog : WidgetHandler Control.Filename ?? Control.CurrentName; +#else + get => Control.Filename; +#endif set { - Control.SetCurrentFolder(Path.GetDirectoryName(value)); - Control.SetFilename(value); - Control.CurrentName = Path.GetFileName(value); + if (string.IsNullOrEmpty(value)) + { + Control.UnselectAll(); + if (!string.IsNullOrEmpty(Control.Filename)) + Control.UnselectFilename(Control.Filename); + } + else + { + var dir = Path.GetDirectoryName(value); + if (!string.IsNullOrEmpty(dir)) + Control.SetCurrentFolder(dir); + if (File.Exists(value)) + Control.SetFilename(value); + } + Control.CurrentName = Path.GetFileName(value) ?? string.Empty; } } @@ -79,7 +95,7 @@ public string Title } - public DialogResult ShowDialog(Window parent) + public virtual DialogResult ShowDialog(Window parent) { SetFilters(); if (parent != null) Control.TransientFor = (Gtk.Window)parent.ControlObject; diff --git a/src/Eto.Gtk/Forms/OpenFileDialog.cs b/src/Eto.Gtk/Forms/OpenFileDialogHandler.cs similarity index 51% rename from src/Eto.Gtk/Forms/OpenFileDialog.cs rename to src/Eto.Gtk/Forms/OpenFileDialogHandler.cs index edb56ef831..c66658314e 100644 --- a/src/Eto.Gtk/Forms/OpenFileDialog.cs +++ b/src/Eto.Gtk/Forms/OpenFileDialogHandler.cs @@ -1,15 +1,18 @@ using Eto.Forms; using System.Collections.Generic; +using System.IO; namespace Eto.GtkSharp.Forms { public class OpenFileDialogHandler : GtkFileDialog, OpenFileDialog.IHandler { + string fileName; + public OpenFileDialogHandler() { Control = new Gtk.FileChooserDialog(string.Empty, null, Gtk.FileChooserAction.Open); Control.SetCurrentFolder(System.IO.Directory.GetCurrentDirectory()); - + Control.AddButton(Gtk.Stock.Cancel, Gtk.ResponseType.Cancel); Control.AddButton(Gtk.Stock.Open, Gtk.ResponseType.Ok); Control.DefaultResponse = Gtk.ResponseType.Ok; @@ -18,7 +21,7 @@ public OpenFileDialogHandler() public bool MultiSelect { get { return Control.SelectMultiple; } - set { Control.SelectMultiple = value; } + set { Control.SelectMultiple = value; } } public IEnumerable Filenames @@ -26,5 +29,24 @@ public IEnumerable Filenames get { return Control.Filenames; } } + public override string FileName + { + get => base.FileName ?? fileName; + set => base.FileName = fileName = value; + } + + public override DialogResult ShowDialog(Window parent) + { + var result = base.ShowDialog(parent); + + // When cancelling, Control.Filename all of the sudden returns a value but is just the folder. + // so, combine it with the desired file name, if one was set. + if (result == DialogResult.Ok) + fileName = null; + else if (!string.IsNullOrEmpty(fileName) && string.IsNullOrEmpty(Path.GetDirectoryName(fileName))) + Control.SetFilename(Path.Combine(base.FileName, fileName)); + return result; + } + } } diff --git a/src/Eto.Gtk/Forms/SaveFileDialog.cs b/src/Eto.Gtk/Forms/SaveFileDialogHandler.cs similarity index 100% rename from src/Eto.Gtk/Forms/SaveFileDialog.cs rename to src/Eto.Gtk/Forms/SaveFileDialogHandler.cs diff --git a/src/Eto.Mac/Forms/MacFileDialog.cs b/src/Eto.Mac/Forms/MacFileDialog.cs index a7d552009e..c21346339d 100644 --- a/src/Eto.Mac/Forms/MacFileDialog.cs +++ b/src/Eto.Mac/Forms/MacFileDialog.cs @@ -92,25 +92,18 @@ void Create() Control.AccessoryView = null; } + string fileName; + public virtual string FileName { - get - { - return Control.Url.Path; - } - set { } + get => Control.Url?.Path ?? fileName; + set => fileName = value; } public Uri Directory { - get - { - return new Uri(Control.DirectoryUrl.AbsoluteString); - } - set - { - Control.DirectoryUrl = new NSUrl(value.AbsoluteUri); - } + get => new Uri(Control.DirectoryUrl.AbsoluteString); + set => Control.DirectoryUrl = new NSUrl(value.AbsoluteUri); } public string GetDefaultExtension() @@ -173,15 +166,18 @@ public string Title get { return Control.Message; } set { Control.Message = value ?? string.Empty; } } - - public DialogResult ShowDialog(Window parent) + + public virtual DialogResult ShowDialog(Window parent) { //Control.AllowsOtherFileTypes = false; Control.Delegate = new SavePanelDelegate{ Handler = this }; Create(); int ret = MacModal.Run(Control, parent); - + + if (ret == 1) + fileName = null; + return ret == 1 ? DialogResult.Ok : DialogResult.Cancel; } diff --git a/src/Eto.Mac/Forms/OpenFileDialog.cs b/src/Eto.Mac/Forms/OpenFileDialogHandler.cs similarity index 100% rename from src/Eto.Mac/Forms/OpenFileDialog.cs rename to src/Eto.Mac/Forms/OpenFileDialogHandler.cs diff --git a/src/Eto.Mac/Forms/SaveFileDialogHandler.cs b/src/Eto.Mac/Forms/SaveFileDialogHandler.cs index e7443dfa43..22a1e64997 100644 --- a/src/Eto.Mac/Forms/SaveFileDialogHandler.cs +++ b/src/Eto.Mac/Forms/SaveFileDialogHandler.cs @@ -5,15 +5,15 @@ namespace Eto.Mac.Forms { public class SaveFileDialogHandler : MacFileDialog, SaveFileDialog.IHandler { + bool hasShown; + public override string FileName { - get - { - return base.FileName; - } + get => hasShown ? base.FileName : Control.NameFieldStringValue; set { - Control.NameFieldStringValue = value; + Control.NameFieldStringValue = value ?? string.Empty; + hasShown = false; } } @@ -30,5 +30,14 @@ protected override void Initialize() Control.CanSelectHiddenExtension = true; base.Initialize(); } + + public override DialogResult ShowDialog(Window parent) + { + hasShown = true; + var result = base.ShowDialog(parent); + if (result != DialogResult.Ok) + hasShown = false; + return result; + } } } diff --git a/src/Eto.WinForms/Forms/OpenFileDialog.cs b/src/Eto.WinForms/Forms/OpenFileDialogHandler.cs similarity index 100% rename from src/Eto.WinForms/Forms/OpenFileDialog.cs rename to src/Eto.WinForms/Forms/OpenFileDialogHandler.cs diff --git a/src/Eto.WinForms/Forms/SaveFileDialog.cs b/src/Eto.WinForms/Forms/SaveFileDialogHandler.cs similarity index 100% rename from src/Eto.WinForms/Forms/SaveFileDialog.cs rename to src/Eto.WinForms/Forms/SaveFileDialogHandler.cs diff --git a/test/Eto.Test/UnitTests/Forms/FileDialogTests.cs b/test/Eto.Test/UnitTests/Forms/FileDialogTests.cs new file mode 100644 index 0000000000..a477fc7e02 --- /dev/null +++ b/test/Eto.Test/UnitTests/Forms/FileDialogTests.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Eto.Drawing; +using Eto.Forms; +using NUnit.Framework; + +namespace Eto.Test.UnitTests.Forms +{ + [TestFixture] + public class OpenFileDialogTests : FileDialogTests + { + } + + [TestFixture] + public class SaveFileDialogTests : FileDialogTests + { + } + + public class FileDialogTests : TestBase + where T: FileDialog, new() + { + [Test, InvokeOnUI, ManualTest] + public void FileNameShouldHaveConsistentValues() + { + var fd = new T(); + fd.Filters.Add(new FileFilter("Text Files (*.txt)", ".txt")); + + Assert.That(fd.FileName, Is.Null.Or.Empty.Or.EqualTo("Untitled"), "#1"); + + fd.FileName = null; + Assert.That(fd.FileName, Is.Null.Or.Empty.Or.EqualTo("Untitled"), "#2"); + + fd.FileName = "SomeFile.txt"; + + Assert.AreEqual("SomeFile.txt", Path.GetFileName(fd.FileName), "#3"); + + var result = fd.ShowDialog(null); + + if (result == DialogResult.Cancel || typeof(T) == typeof(SaveFileDialog)) + Assert.AreEqual("SomeFile.txt", Path.GetFileName(fd.FileName), "#4"); + + if (result == DialogResult.Ok) + { + var directoryName = Path.GetDirectoryName(fd.FileName); + Assert.IsNotNull(directoryName, "#5.1"); + Assert.IsNotEmpty(directoryName, "#5.2"); + Console.WriteLine($"Directory: {directoryName}"); + } + + Console.WriteLine($"FileName: {fd.FileName}"); + + } + } +}