mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* WIP keep path * Make new 'sticky filename' behaviour optional * Tests for new behaviour when selecting in TreeView * Add more tests, this time for table view navigation * Add the new style option into UICatalog scenario
This commit is contained in:
@@ -16,6 +16,7 @@ public class FileDialogExamples : Scenario
|
||||
private CheckBox _cbAlwaysTableShowHeaders;
|
||||
private CheckBox _cbCaseSensitive;
|
||||
private CheckBox _cbDrivesOnlyInTree;
|
||||
private CheckBox _cbPreserveFilenameOnDirectoryChanges;
|
||||
private CheckBox _cbFlipButtonOrder;
|
||||
private CheckBox _cbMustExist;
|
||||
private CheckBox _cbShowTreeBranchLines;
|
||||
@@ -55,6 +56,9 @@ public class FileDialogExamples : Scenario
|
||||
_cbDrivesOnlyInTree = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Only Show _Drives" };
|
||||
win.Add (_cbDrivesOnlyInTree);
|
||||
|
||||
_cbPreserveFilenameOnDirectoryChanges = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Preserve Filename" };
|
||||
win.Add (_cbPreserveFilenameOnDirectoryChanges);
|
||||
|
||||
y = 0;
|
||||
x = 24;
|
||||
|
||||
@@ -198,6 +202,9 @@ public class FileDialogExamples : Scenario
|
||||
fd.Style.TreeRootGetter = () => { return Environment.GetLogicalDrives ().ToDictionary (dirInfoFactory.New, k => k); };
|
||||
}
|
||||
|
||||
fd.Style.PreserveFilenameOnDirectoryChanges = _cbPreserveFilenameOnDirectoryChanges.CheckedState == CheckState.Checked;
|
||||
|
||||
|
||||
if (_rgAllowedTypes.SelectedItem > 0)
|
||||
{
|
||||
fd.AllowedTypes.Add (new AllowedType ("Data File", ".csv", ".tsv"));
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Terminal.Gui;
|
||||
public class FileDialogStyle
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private bool _preserveFilenameOnDirectoryChanges;
|
||||
|
||||
/// <summary>Creates a new instance of the <see cref="FileDialogStyle"/> class.</summary>
|
||||
public FileDialogStyle (IFileSystem fileSystem)
|
||||
@@ -144,6 +145,21 @@ public class FileDialogStyle
|
||||
/// </summary>
|
||||
public string WrongFileTypeFeedback { get; set; } = Strings.fdWrongFileTypeFeedback;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Gets or sets a flag that determines behaviour when opening (double click/enter) or selecting a
|
||||
/// directory in a <see cref="FileDialog"/>.
|
||||
/// </para>
|
||||
/// <para>If <see langword="false"/> (the default) then the <see cref="FileDialog.Path"/> is simply
|
||||
/// updated to the new directory path.</para>
|
||||
/// <para>If <see langword="true"/> then any typed or previously selected file
|
||||
/// name is preserved (e.g. "c:/hello.csv" when opening "temp" becomes "c:/temp/hello.csv").
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool PreserveFilenameOnDirectoryChanges { get; set; }
|
||||
|
||||
|
||||
[UnconditionalSuppressMessage ("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
|
||||
private Dictionary<IDirectoryInfo, string> DefaultTreeRootGetter ()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@ using System.IO.Abstractions;
|
||||
using System.Text.RegularExpressions;
|
||||
using Terminal.Gui.Resources;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
@@ -1135,7 +1137,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
}
|
||||
else if (setPathText)
|
||||
{
|
||||
Path = newState.Directory.FullName;
|
||||
SetPathToSelectedObject (newState.Directory);
|
||||
}
|
||||
|
||||
State = newState;
|
||||
@@ -1393,7 +1395,7 @@ public class FileDialog : Dialog, IDesignable
|
||||
{
|
||||
_pushingState = true;
|
||||
|
||||
Path = dest.FullName;
|
||||
SetPathToSelectedObject (dest);
|
||||
State.Selected = stats;
|
||||
_tbPath.Autocomplete.ClearSuggestions ();
|
||||
}
|
||||
@@ -1405,12 +1407,32 @@ public class FileDialog : Dialog, IDesignable
|
||||
|
||||
private void TreeView_SelectionChanged (object sender, SelectionChangedEventArgs<IFileSystemInfo> e)
|
||||
{
|
||||
if (e.NewValue is null)
|
||||
SetPathToSelectedObject (e.NewValue);
|
||||
}
|
||||
|
||||
private void SetPathToSelectedObject (IFileSystemInfo? selected)
|
||||
{
|
||||
if (selected is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Path = e.NewValue.FullName;
|
||||
if (selected is IDirectoryInfo && Style.PreserveFilenameOnDirectoryChanges)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace (Path) && !_fileSystem.Directory.Exists (Path))
|
||||
{
|
||||
var currentFile = _fileSystem.Path.GetFileName (Path);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace (currentFile))
|
||||
{
|
||||
Path = _fileSystem.Path.Combine (selected.FullName, currentFile);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Path = selected.FullName;
|
||||
}
|
||||
|
||||
private bool TryAcceptMulti ()
|
||||
|
||||
@@ -189,4 +189,174 @@ public class FileDialogFluentTests
|
||||
.WriteOutLogs (_out)
|
||||
.Stop ();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData (typeof (V2TestDrivers))]
|
||||
public void SaveFileDialog_PopTree_AndNavigate_PreserveFilenameOnDirectoryChanges_True (V2TestDriver d)
|
||||
{
|
||||
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
|
||||
sd.Style.PreserveFilenameOnDirectoryChanges = true;
|
||||
|
||||
using var c = With.A (sd, 100, 20, d)
|
||||
.ScreenShot ("Save dialog", _out)
|
||||
.Then (() => Assert.True (sd.Canceled))
|
||||
.Focus<TextField> (_=>true)
|
||||
// Clear selection by pressing right in 'file path' text box
|
||||
.RaiseKeyDownEvent (Key.CursorRight)
|
||||
.AssertIsType <TextField>(sd.Focused)
|
||||
// Type a filename into the dialog
|
||||
.RaiseKeyDownEvent (Key.H)
|
||||
.RaiseKeyDownEvent (Key.E)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.O)
|
||||
.WaitIteration ()
|
||||
.ScreenShot ("After typing filename 'hello'", _out)
|
||||
.AssertEndsWith ("hello", sd.Path)
|
||||
.LeftClick<Button> (b => b.Text == "►►")
|
||||
.ScreenShot ("After pop tree", _out)
|
||||
.Focus<TreeView<IFileSystemInfo>> (_ => true)
|
||||
.Right ()
|
||||
.ScreenShot ("After expand tree", _out)
|
||||
// Because of PreserveFilenameOnDirectoryChanges we should select the new dir but keep the filename
|
||||
.AssertEndsWith ("hello", sd.Path)
|
||||
.Down ()
|
||||
.ScreenShot ("After navigate down in tree", _out)
|
||||
// Because of PreserveFilenameOnDirectoryChanges we should select the new dir but keep the filename
|
||||
.AssertContains ("empty-dir",sd.Path)
|
||||
.AssertEndsWith ("hello", sd.Path)
|
||||
.Enter ()
|
||||
.WaitIteration ()
|
||||
.Then (() => Assert.False (sd.Canceled))
|
||||
.AssertContains ("empty-dir", sd.FileName)
|
||||
.WriteOutLogs (_out)
|
||||
.Stop ();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData (typeof (V2TestDrivers))]
|
||||
public void SaveFileDialog_PopTree_AndNavigate_PreserveFilenameOnDirectoryChanges_False (V2TestDriver d)
|
||||
{
|
||||
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
|
||||
sd.Style.PreserveFilenameOnDirectoryChanges = false;
|
||||
|
||||
using var c = With.A (sd, 100, 20, d)
|
||||
.ScreenShot ("Save dialog", _out)
|
||||
.Then (() => Assert.True (sd.Canceled))
|
||||
.Focus<TextField> (_ => true)
|
||||
// Clear selection by pressing right in 'file path' text box
|
||||
.RaiseKeyDownEvent (Key.CursorRight)
|
||||
.AssertIsType<TextField> (sd.Focused)
|
||||
// Type a filename into the dialog
|
||||
.RaiseKeyDownEvent (Key.H)
|
||||
.RaiseKeyDownEvent (Key.E)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.O)
|
||||
.WaitIteration ()
|
||||
.ScreenShot ("After typing filename 'hello'", _out)
|
||||
.AssertEndsWith ("hello", sd.Path)
|
||||
.LeftClick<Button> (b => b.Text == "►►")
|
||||
.ScreenShot ("After pop tree", _out)
|
||||
.Focus<TreeView<IFileSystemInfo>> (_ => true)
|
||||
.Right ()
|
||||
.ScreenShot ("After expand tree", _out)
|
||||
.Down ()
|
||||
.ScreenShot ("After navigate down in tree", _out)
|
||||
// PreserveFilenameOnDirectoryChanges is false so just select new path
|
||||
.AssertEndsWith ("empty-dir", sd.Path)
|
||||
.AssertDoesNotContain ("hello", sd.Path)
|
||||
.Enter ()
|
||||
.WaitIteration ()
|
||||
.Then (() => Assert.False (sd.Canceled))
|
||||
.AssertContains ("empty-dir", sd.FileName)
|
||||
.WriteOutLogs (_out)
|
||||
.Stop ();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData (typeof (V2TestDrivers_WithTrueFalseParameter))]
|
||||
public void SaveFileDialog_TableView_UpDown_PreserveFilenameOnDirectoryChanges_True (V2TestDriver d, bool preserve)
|
||||
{
|
||||
var sd = new SaveDialog (CreateExampleFileSystem ()) { Modal = false };
|
||||
sd.Style.PreserveFilenameOnDirectoryChanges = preserve;
|
||||
|
||||
using var c = With.A (sd, 100, 20, d)
|
||||
.ScreenShot ("Save dialog", _out)
|
||||
.Then (() => Assert.True (sd.Canceled))
|
||||
.Focus<TextField> (_ => true)
|
||||
// Clear selection by pressing right in 'file path' text box
|
||||
.RaiseKeyDownEvent (Key.CursorRight)
|
||||
.AssertIsType<TextField> (sd.Focused)
|
||||
// Type a filename into the dialog
|
||||
.RaiseKeyDownEvent (Key.H)
|
||||
.RaiseKeyDownEvent (Key.E)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.L)
|
||||
.RaiseKeyDownEvent (Key.O)
|
||||
.WaitIteration ()
|
||||
.ScreenShot ("After typing filename 'hello'", _out)
|
||||
.AssertEndsWith ("hello", sd.Path)
|
||||
.Focus<TableView> (_ => true)
|
||||
.ScreenShot ("After focus table", _out)
|
||||
.Down ()
|
||||
.ScreenShot ("After down in table", _out);
|
||||
|
||||
if (preserve)
|
||||
{
|
||||
c.AssertContains ("logs", sd.Path)
|
||||
.AssertEndsWith ("hello", sd.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.AssertContains ("logs", sd.Path)
|
||||
.AssertDoesNotContain ("hello", sd.Path);
|
||||
}
|
||||
|
||||
c.Up ()
|
||||
.ScreenShot ("After up in table", _out);
|
||||
|
||||
if (preserve)
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertEndsWith ("hello", sd.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertDoesNotContain ("hello", sd.Path);
|
||||
}
|
||||
|
||||
c.Enter ()
|
||||
.ScreenShot ("After enter in table", _out); ;
|
||||
|
||||
|
||||
if (preserve)
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertEndsWith ("hello", sd.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertDoesNotContain ("hello", sd.Path);
|
||||
}
|
||||
|
||||
c.LeftClick<Button> (b => b.Text == "_Save");
|
||||
c.AssertFalse (sd.Canceled);
|
||||
|
||||
if (preserve)
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertEndsWith ("hello", sd.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.AssertContains ("empty-dir", sd.Path)
|
||||
.AssertDoesNotContain ("hello", sd.Path);
|
||||
}
|
||||
|
||||
c.WriteOutLogs (_out)
|
||||
.Stop ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,3 +13,20 @@ public class V2TestDrivers : IEnumerable<object []>
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test cases for functions with signature <code>V2TestDriver d, bool someFlag</code>
|
||||
/// that enumerates all variations
|
||||
/// </summary>
|
||||
public class V2TestDrivers_WithTrueFalseParameter : IEnumerable<object []>
|
||||
{
|
||||
public IEnumerator<object []> GetEnumerator ()
|
||||
{
|
||||
yield return new object [] { V2TestDriver.V2Win,false };
|
||||
yield return new object [] { V2TestDriver.V2Net,false };
|
||||
yield return new object [] { V2TestDriver.V2Win,true };
|
||||
yield return new object [] { V2TestDriver.V2Net,true };
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
|
||||
}
|
||||
Reference in New Issue
Block a user