using System.Data; #nullable enable using JetBrains.Annotations; namespace ViewsTests; [TestSubject (typeof (TableView))] public class TableViewTests { [Fact] public void CanTabOutOfTableViewUsingCursor_Left () { GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2); // Make the selected cell one in tableView.SelectedColumn = 1; // Pressing left should move us to the first column without changing focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorLeft); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); // Because we are now on the leftmost cell a further left press should move focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorLeft); Assert.NotSame (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.False (tableView.HasFocus); Assert.Same (tf1, tableView.App!.TopRunnableView.MostFocused); Assert.True (tf1.HasFocus); } [Fact] public void CanTabOutOfTableViewUsingCursor_Up () { GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2); // Make the selected cell one in tableView.SelectedRow = 1; // First press should move us up tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorUp); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); // Because we are now on the top row a further press should move focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorUp); Assert.NotSame (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.False (tableView.HasFocus); Assert.Same (tf1, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tf1.HasFocus); } [Fact] public void CanTabOutOfTableViewUsingCursor_Right () { GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2); // Make the selected cell one in from the rightmost column tableView.SelectedColumn = tableView.Table.Columns - 2; // First press should move us to the rightmost column without changing focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorRight); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); // Because we are now on the rightmost cell, a further right press should move focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorRight); Assert.NotSame (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.False (tableView.HasFocus); Assert.Same (tf2, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tf2.HasFocus); } [Fact] public void CanTabOutOfTableViewUsingCursor_Down () { GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2); // Make the selected cell one in from the bottommost row tableView.SelectedRow = tableView.Table.Rows - 2; // First press should move us to the bottommost row without changing focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorDown); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); // Because we are now on the bottommost cell, a further down press should move focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorDown); Assert.NotSame (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.False (tableView.HasFocus); Assert.Same (tf2, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tf2.HasFocus); } [Fact] public void CanTabOutOfTableViewUsingCursor_Left_ClearsSelectionFirst () { GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2); // Make the selected cell one in tableView.SelectedColumn = 1; // Pressing shift-left should give us a multi selection tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorLeft.WithShift); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); Assert.Equal (2, tableView.GetAllSelectedCells ().Count ()); // Because we are now on the leftmost cell a further left press would normally move focus // However there is an ongoing selection so instead the operation clears the selection and // gets swallowed (not resulting in a focus change) tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorLeft); // Selection 'clears' just to the single cell and we remain focused Assert.Single (tableView.GetAllSelectedCells ()); Assert.Same (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tableView.HasFocus); // A further left will switch focus tableView.App!.Keyboard.RaiseKeyDownEvent (Key.CursorLeft); Assert.NotSame (tableView, tableView.App!.TopRunnableView!.MostFocused); Assert.False (tableView.HasFocus); Assert.Same (tf1, tableView.App!.TopRunnableView!.MostFocused); Assert.True (tf1.HasFocus); } /// /// Creates 3 views on with the focus in the /// . This is a helper method to setup tests that want to /// explore moving input focus out of a tableview. /// /// /// /// private void GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2) { IApplication? app = Application.Create (); Runnable? runnable = new (); app.Begin (runnable); tableView = new (); tf1 = new (); tf2 = new (); runnable.Add (tf1); runnable.Add (tableView); runnable.Add (tf2); tableView.SetFocus (); Assert.Same (tableView, runnable.MostFocused); Assert.True (tableView.HasFocus); // Set big table tableView.Table = BuildTable (25, 50); } public static DataTableSource BuildTable (int cols, int rows) => BuildTable (cols, rows, out _); /// Builds a simple table of string columns with the requested number of columns and rows /// /// /// public static DataTableSource BuildTable (int cols, int rows, out DataTable dt) { dt = new (); for (var c = 0; c < cols; c++) { dt.Columns.Add ("Col" + c); } for (var r = 0; r < rows; r++) { DataRow newRow = dt.NewRow (); for (var c = 0; c < cols; c++) { newRow [c] = $"R{r}C{c}"; } dt.Rows.Add (newRow); } return new (dt); } [Fact] public void TableView_CollectionNavigatorMatcher_KeybindingsOverrideNavigator () { var dt = new DataTable (); dt.Columns.Add ("blah"); dt.Rows.Add ("apricot"); dt.Rows.Add ("arm"); dt.Rows.Add ("bat"); dt.Rows.Add ("batman"); dt.Rows.Add ("bates hotel"); dt.Rows.Add ("candle"); var tableView = new TableView (); tableView.Table = new DataTableSource (dt); tableView.HasFocus = true; tableView.KeyBindings.Add (Key.B, Command.Down); Assert.Equal (0, tableView.SelectedRow); // Keys should be consumed to move down the navigation i.e. to apricot Assert.True (tableView.NewKeyDownEvent (Key.B)); Assert.Equal (1, tableView.SelectedRow); Assert.True (tableView.NewKeyDownEvent (Key.B)); Assert.Equal (2, tableView.SelectedRow); // There is no keybinding for Key.C so it hits collection navigator i.e. we jump to candle Assert.True (tableView.NewKeyDownEvent (Key.C)); Assert.Equal (5, tableView.SelectedRow); } }