Skip to content

Commit d2d08de

Browse files
authored
Fixes #174. Changing Filter does not undo previously marked items (#186)
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
1 parent 3545bdc commit d2d08de

File tree

3 files changed

+52
-15
lines changed

3 files changed

+52
-15
lines changed

src/Microsoft.PowerShell.ConsoleGuiTools/ConsoleGui.cs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@ internal class ConsoleGui : IDisposable
2222
private Label _filterLabel;
2323
private TextField _filterField;
2424
private ListView _listView;
25-
private GridViewDataSource _itemSource;
25+
// _inputSource contains the full set of Input data and tracks any items the user
26+
// marks. When the cmdlet exits, any marked items are returned. When a filter is
27+
// active, the list view shows a copy of _inputSource that includes both the items
28+
// matching the filter AND any items previously marked.
29+
private GridViewDataSource _inputSource;
30+
31+
// _listViewSource is a filtered copy of _inputSource that ListView.Source is set to.
32+
// Changes to IsMarked are propogated back to _inputSource.
33+
private GridViewDataSource _listViewSource;
2634
private ApplicationData _applicationData;
2735
private GridViewDetails _gridViewDetails;
2836

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

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

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

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

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

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

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

121131
private void ApplyFilter()
122132
{
123-
List<GridViewRow> itemList = GridViewHelpers.FilterData(_itemSource.GridViewRowList, _applicationData.Filter ?? string.Empty);
124-
// Set the ListView to show only the subset defined by the filter
125-
_listView.Source = new GridViewDataSource(itemList);
133+
// The ListView is always filled with a (filtered) copy of _inputSource.
134+
// We listen for `MarkChanged` events on this filtered list and apply those changes up to _inputSource.
135+
136+
if (_listViewSource != null) {
137+
_listViewSource.MarkChanged -= ListViewSource_MarkChanged;
138+
_listViewSource = null;
139+
}
140+
141+
_listViewSource = new GridViewDataSource(GridViewHelpers.FilterData(_inputSource.GridViewRowList, _applicationData.Filter ?? string.Empty));
142+
_listViewSource.MarkChanged += ListViewSource_MarkChanged;
143+
_listView.Source = _listViewSource;
144+
}
145+
146+
private void ListViewSource_MarkChanged (object s, GridViewDataSource.RowMarkedEventArgs a)
147+
{
148+
_inputSource.GridViewRowList[a.Row.OriginalIndex].IsMarked = a.Row.IsMarked;
126149
}
127150

128151
private void Accept()
@@ -198,7 +221,7 @@ private void AddStatusBar(bool visible)
198221
// when ENTER is pressed in Single mode. If something was previously selected
199222
// (using SPACE) then honor that as the single item to return
200223
if (_applicationData.OutputMode == OutputModeOption.Single &&
201-
_itemSource.GridViewRowList.Find(i => i.IsMarked) == null)
224+
_inputSource.GridViewRowList.Find(i => i.IsMarked) == null)
202225
{
203226
_listView.MarkUnmarkRow();
204227
}
@@ -315,7 +338,7 @@ private void AddFilter(Window win)
315338
filterErrorLabel.Text = ex.Message;
316339
filterErrorLabel.ColorScheme = Colors.Error;
317340
filterErrorLabel.Redraw(filterErrorLabel.Bounds);
318-
_listView.Source = _itemSource;
341+
_listView.Source = _inputSource;
319342
}
320343
};
321344

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

371394
private void AddListView(Window win)
372395
{
373-
_listView = new ListView(_itemSource);
396+
_listView = new ListView(_inputSource);
374397
_listView.X = MARGIN_LEFT;
375398
if (!_applicationData.MinUI)
376399
{

src/Microsoft.PowerShell.ConsoleGuiTools/GridViewDataSource.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,23 @@ public void Render(ListView container, ConsoleDriver driver, bool selected, int
3232

3333
public void SetMark(int item, bool value)
3434
{
35+
var oldValue = GridViewRowList[item].IsMarked;
3536
GridViewRowList[item].IsMarked = value;
37+
var args = new RowMarkedEventArgs() {
38+
Row = GridViewRowList[item],
39+
OldValue = oldValue
40+
};
41+
MarkChanged?.Invoke(this, args);
3642
}
3743

44+
public class RowMarkedEventArgs : EventArgs {
45+
public GridViewRow Row { get; set;}
46+
public bool OldValue { get ; set;}
47+
48+
}
49+
50+
public event EventHandler<RowMarkedEventArgs> MarkChanged;
51+
3852
public IList ToList()
3953
{
4054
return GridViewRowList;

src/Microsoft.PowerShell.ConsoleGuiTools/GridViewHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static List<GridViewRow> FilterData(List<GridViewRow> list, string filter
2424

2525
foreach (GridViewRow gvr in list)
2626
{
27-
if(Regex.IsMatch(gvr.DisplayString, filter, RegexOptions.IgnoreCase))
27+
if (gvr.IsMarked || Regex.IsMatch(gvr.DisplayString, filter, RegexOptions.IgnoreCase))
2828
{
2929
items.Add(gvr);
3030
}

0 commit comments

Comments
 (0)