Skip to content

Commit

Permalink
Fixes #174. Changing Filter does not undo previously marked items (#186)
Browse files Browse the repository at this point in the history
This addresses #174 (changing the filter caused marked items to get unmarked) by:

- The input to the cmdlet tracks marked/unmarked items
- The list attached to the listview is now always a copy of the input list, with the filter applied (even if there's no fitler).
- Whenever mark/unmark happens in the listview, the original item in the input list is updated
- On exit, any items in the input list that are marked are provided as output
  • Loading branch information
tig authored May 3, 2023
1 parent 3545bdc commit d2d08de
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 15 deletions.
51 changes: 37 additions & 14 deletions src/Microsoft.PowerShell.ConsoleGuiTools/ConsoleGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ internal class ConsoleGui : IDisposable
private Label _filterLabel;
private TextField _filterField;
private ListView _listView;
private GridViewDataSource _itemSource;
// _inputSource contains the full set of Input data and tracks any items the user
// marks. When the cmdlet exits, any marked items are returned. When a filter is
// active, the list view shows a copy of _inputSource that includes both the items
// matching the filter AND any items previously marked.
private GridViewDataSource _inputSource;

// _listViewSource is a filtered copy of _inputSource that ListView.Source is set to.
// Changes to IsMarked are propogated back to _inputSource.
private GridViewDataSource _listViewSource;
private ApplicationData _applicationData;
private GridViewDetails _gridViewDetails;

Expand All @@ -43,8 +51,9 @@ public HashSet<int> Start(ApplicationData applicationData)
List<string> gridHeaders = _applicationData.DataTable.DataColumns.Select((c) => c.Label).ToList();
CalculateColumnWidths(gridHeaders);

// Copy DataTable into the ListView's DataSource
_itemSource = LoadData();
// Copy the input DataTable into our master ListView source list; upon exit any items
// that are IsMarked are returned (if Outputmode is set)
_inputSource = LoadData();

if (!_applicationData.MinUI)
{
Expand All @@ -60,7 +69,9 @@ public HashSet<int> Start(ApplicationData applicationData)
// Status bar is where our key-bindings are handled
AddStatusBar(!_applicationData.MinUI);

// If -Filter parameter is set, apply it.
// We *always* apply a filter, even if the -Filter parameter is not set or Filtering is not
// available. The ListView always shows a fitlered version of _inputSource even if there is no
// actual fitler.
ApplyFilter();

_listView.SetFocus();
Expand All @@ -76,10 +87,8 @@ public HashSet<int> Start(ApplicationData applicationData)
return selectedIndexes;
}

// Ensure that only items that are marked AND not filtered out
// get returned (See Issue #121)
List<GridViewRow> itemList = GridViewHelpers.FilterData(_itemSource.GridViewRowList, _applicationData.Filter);
foreach (GridViewRow gvr in itemList)
// Return any items that were selected.
foreach (GridViewRow gvr in _inputSource.GridViewRowList)
{
if (gvr.IsMarked)
{
Expand Down Expand Up @@ -109,6 +118,7 @@ private GridViewDataSource LoadData()
items.Add(new GridViewRow
{
DisplayString = displayString,
// We use this to keep _inputSource up to date when a filter is applied
OriginalIndex = i
});

Expand All @@ -120,9 +130,22 @@ private GridViewDataSource LoadData()

private void ApplyFilter()
{
List<GridViewRow> itemList = GridViewHelpers.FilterData(_itemSource.GridViewRowList, _applicationData.Filter ?? string.Empty);
// Set the ListView to show only the subset defined by the filter
_listView.Source = new GridViewDataSource(itemList);
// The ListView is always filled with a (filtered) copy of _inputSource.
// We listen for `MarkChanged` events on this filtered list and apply those changes up to _inputSource.

if (_listViewSource != null) {
_listViewSource.MarkChanged -= ListViewSource_MarkChanged;
_listViewSource = null;
}

_listViewSource = new GridViewDataSource(GridViewHelpers.FilterData(_inputSource.GridViewRowList, _applicationData.Filter ?? string.Empty));
_listViewSource.MarkChanged += ListViewSource_MarkChanged;
_listView.Source = _listViewSource;
}

private void ListViewSource_MarkChanged (object s, GridViewDataSource.RowMarkedEventArgs a)
{
_inputSource.GridViewRowList[a.Row.OriginalIndex].IsMarked = a.Row.IsMarked;
}

private void Accept()
Expand Down Expand Up @@ -198,7 +221,7 @@ private void AddStatusBar(bool visible)
// when ENTER is pressed in Single mode. If something was previously selected
// (using SPACE) then honor that as the single item to return
if (_applicationData.OutputMode == OutputModeOption.Single &&
_itemSource.GridViewRowList.Find(i => i.IsMarked) == null)
_inputSource.GridViewRowList.Find(i => i.IsMarked) == null)
{
_listView.MarkUnmarkRow();
}
Expand Down Expand Up @@ -315,7 +338,7 @@ private void AddFilter(Window win)
filterErrorLabel.Text = ex.Message;
filterErrorLabel.ColorScheme = Colors.Error;
filterErrorLabel.Redraw(filterErrorLabel.Bounds);
_listView.Source = _itemSource;
_listView.Source = _inputSource;
}
};

Expand Down Expand Up @@ -370,7 +393,7 @@ private void AddHeaders(Window win, List<string> gridHeaders)

private void AddListView(Window win)
{
_listView = new ListView(_itemSource);
_listView = new ListView(_inputSource);
_listView.X = MARGIN_LEFT;
if (!_applicationData.MinUI)
{
Expand Down
14 changes: 14 additions & 0 deletions src/Microsoft.PowerShell.ConsoleGuiTools/GridViewDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,23 @@ public void Render(ListView container, ConsoleDriver driver, bool selected, int

public void SetMark(int item, bool value)
{
var oldValue = GridViewRowList[item].IsMarked;
GridViewRowList[item].IsMarked = value;
var args = new RowMarkedEventArgs() {
Row = GridViewRowList[item],
OldValue = oldValue
};
MarkChanged?.Invoke(this, args);
}

public class RowMarkedEventArgs : EventArgs {
public GridViewRow Row { get; set;}
public bool OldValue { get ; set;}

}

public event EventHandler<RowMarkedEventArgs> MarkChanged;

public IList ToList()
{
return GridViewRowList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static List<GridViewRow> FilterData(List<GridViewRow> list, string filter

foreach (GridViewRow gvr in list)
{
if(Regex.IsMatch(gvr.DisplayString, filter, RegexOptions.IgnoreCase))
if (gvr.IsMarked || Regex.IsMatch(gvr.DisplayString, filter, RegexOptions.IgnoreCase))
{
items.Add(gvr);
}
Expand Down

0 comments on commit d2d08de

Please sign in to comment.