Skip to content

Commit e74ba3c

Browse files
authored
Merge pull request #4217 from IvenBach/Issue4159
Allow filtering of results in CodeInspections window
2 parents 91cf0d8 + 8ee0a23 commit e74ba3c

13 files changed

+410
-154
lines changed

Rubberduck.Core/UI/CodeExplorer/CodeExplorerControl.xaml

Lines changed: 44 additions & 37 deletions
Large diffs are not rendered by default.

Rubberduck.Core/UI/Inspections/InspectionResultsControl.xaml

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
ResxExtension.DefaultResxName="Rubberduck.Resources.RubberduckUI"
1010
Language="{UICulture}"
1111
mc:Ignorable="d"
12-
d:DesignHeight="300" d:DesignWidth="300"
12+
d:DesignHeight="300" d:DesignWidth="500"
1313
d:DataContext="{d:DesignInstance codeInspections:InspectionResultsViewModel}">
1414
<UserControl.Resources>
1515
<ResourceDictionary>
@@ -23,9 +23,7 @@
2323
<codeInspections:InspectionImageSourceConverter x:Key="InspectionIconConverter" />
2424
<codeInspections:InspectionTypeConverter x:Key="InspectionTypeConverter" />
2525

26-
<Style x:Key="IconStyle" TargetType="Image">
27-
<Setter Property="Height" Value="16" />
28-
<Setter Property="Width" Value="16" />
26+
<Style x:Key="IconMargin" TargetType="Image">
2927
<Setter Property="Margin" Value="4" />
3028
</Style>
3129

@@ -41,8 +39,25 @@
4139
</CollectionViewSource.GroupDescriptions>
4240
</CollectionViewSource>
4341

44-
42+
<BitmapImage x:Key="CopyResultsImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/document-copy.png" />
4543
<BitmapImage x:Key="SettingsImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/gear.png" />
44+
<BitmapImage x:Key="RefreshImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/arrow-circle-double.png" />
45+
<BitmapImage x:Key="FixImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/tick.png" />
46+
<BitmapImage x:Key="GroupByImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Custom/PNG/GroupBy.png" />
47+
<BitmapImage x:Key="FilterByHintImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/information-white.png" />
48+
<BitmapImage x:Key="FilterBySuggestionImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/information.png" />
49+
<BitmapImage x:Key="FilterByWarningImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/exclamation.png" />
50+
<BitmapImage x:Key="FilterByErrorImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/cross-circle.png" />
51+
52+
<Style TargetType="Image">
53+
<Setter Property="Height" Value="16"/>
54+
<Setter Property="Width" Value="16" />
55+
</Style>
56+
57+
58+
<Style TargetType="MenuItem">
59+
<Setter Property="VerticalAlignment" Value="Center"/>
60+
</Style>
4661

4762
</ResourceDictionary>
4863
</UserControl.Resources>
@@ -59,7 +74,7 @@
5974
<ToolBar Style="{StaticResource ToolBarWithOverflowOnlyShowingWhenNeededStyle}">
6075

6176
<Button Command="{Binding RefreshCommand}">
62-
<Image Height="16" Source="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/arrow-circle-double.png" />
77+
<Image Source="{StaticResource RefreshImage}" />
6378
</Button>
6479

6580
<Separator />
@@ -68,7 +83,7 @@
6883
Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=Fix}"
6984
ItemsSource="{Binding QuickFixes}">
7085
<MenuItem.Icon>
71-
<Image Height="16" Source="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/tick.png" />
86+
<Image Source="{StaticResource FixImage}" />
7287
</MenuItem.Icon>
7388
<MenuItem.ItemContainerStyle>
7489
<Style TargetType="{x:Type MenuItem}">
@@ -81,11 +96,11 @@
8196
</Menu>
8297

8398
<Menu>
84-
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GroupingGrid_GroupingStyle}" VerticalAlignment="Center">
99+
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GroupingGrid_GroupingStyle}">
85100
<MenuItem.Icon>
86-
<Image Height="16" Source="pack://application:,,,/Rubberduck.Resources;component/Icons/Custom/PNG/GroupBy.png" />
101+
<Image Source="{StaticResource GroupByImage}" />
87102
</MenuItem.Icon>
88-
103+
89104
<MenuItem x:Name="GroupByInspectionType"
90105
Style="{DynamicResource MenuItemStyle}"
91106
VerticalAlignment="Center"
@@ -109,14 +124,58 @@
109124

110125
<Separator />
111126

127+
<Menu>
128+
<MenuItem x:Name="FilterInspectionByError"
129+
Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=InspectionResults_FilterByError}"
130+
IsChecked="{Binding FilterInspectionsByError, UpdateSourceTrigger=PropertyChanged}"
131+
IsCheckable="True"
132+
controls:MenuItemGroup.GroupName="InspectionResults_FilterBy">
133+
<MenuItem.Icon>
134+
<Image Source="{StaticResource FilterByErrorImage}" />
135+
</MenuItem.Icon>
136+
</MenuItem>
137+
138+
<MenuItem x:Name="FilterInspectionByWarning"
139+
Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=InspectionResults_FilterByWarning}"
140+
IsChecked="{Binding FilterInspectionsByWarning, UpdateSourceTrigger=PropertyChanged}"
141+
IsCheckable="True"
142+
controls:MenuItemGroup.GroupName="InspectionResults_FilterBy">
143+
<MenuItem.Icon>
144+
<Image Source="{StaticResource FilterByWarningImage}" />
145+
</MenuItem.Icon>
146+
</MenuItem>
147+
148+
<MenuItem x:Name="FilterInspectionBySuggestion"
149+
Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=InspectionResults_FilterBySuggestion}"
150+
IsChecked="{Binding FilterInspectionsBySuggestion, UpdateSourceTrigger=PropertyChanged}"
151+
IsCheckable="True"
152+
controls:MenuItemGroup.GroupName="InspectionResults_FilterBy">
153+
<MenuItem.Icon>
154+
<Image Source="{StaticResource FilterBySuggestionImage}" />
155+
</MenuItem.Icon>
156+
</MenuItem>
157+
158+
<MenuItem x:Name="FilterInspectionByHint"
159+
Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=InspectionResults_FilterByHint}"
160+
IsChecked="{Binding FilterInspectionsByHint, UpdateSourceTrigger=PropertyChanged}"
161+
IsCheckable="True"
162+
controls:MenuItemGroup.GroupName="InspectionResults_FilterBy">
163+
<MenuItem.Icon>
164+
<Image Source="{StaticResource FilterByHintImage}" />
165+
</MenuItem.Icon>
166+
</MenuItem>
167+
</Menu>
168+
169+
<Separator />
170+
112171
<Button Command="{Binding CopyResultsCommand}">
113-
<Image Height="16" Source="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/document-copy.png" />
172+
<Image Source="{StaticResource CopyResultsImage}" />
114173
<Button.ToolTip>
115174
<TextBlock Text="{Resx ResxName=Rubberduck.Resources.CodeExplorer.CodeExplorerUI, Key=CodeExplorer_CopyToolTip}" />
116175
</Button.ToolTip>
117176
</Button>
118177
<Button ToolTip="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=Settings}" Command="{Binding OpenInspectionSettings}" BorderThickness="0" Background="Transparent">
119-
<Image Height="16" Source="{StaticResource SettingsImage}" />
178+
<Image Source="{StaticResource SettingsImage}" />
120179
</Button>
121180
</ToolBar>
122181
</ToolBarTray>
@@ -132,7 +191,7 @@
132191
<DataGridTemplateColumn Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=CodeInspectionResults_Type}" SortDirection="{Binding}">
133192
<DataGridTemplateColumn.CellTemplate>
134193
<DataTemplate DataType="abstract1:IInspectionResult">
135-
<Image Source="{Binding Inspection, Converter={StaticResource InspectionIconConverter}}" Height="16" />
194+
<Image Source="{Binding Inspection, Converter={StaticResource InspectionIconConverter}}" />
136195
</DataTemplate>
137196
</DataGridTemplateColumn.CellTemplate>
138197
</DataGridTemplateColumn>
@@ -151,7 +210,7 @@
151210
<DataGridTemplateColumn Header="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=CodeInspectionResults_Type}">
152211
<DataGridTemplateColumn.CellTemplate>
153212
<DataTemplate DataType="abstract1:IInspectionResult">
154-
<Image Source="{Binding Inspection, Converter={StaticResource InspectionIconConverter}}" Height="16" />
213+
<Image Source="{Binding Inspection, Converter={StaticResource InspectionIconConverter}}" />
155214
</DataTemplate>
156215
</DataGridTemplateColumn.CellTemplate>
157216
</DataGridTemplateColumn>
@@ -175,7 +234,7 @@
175234
<ColumnDefinition Width="25" />
176235
<ColumnDefinition />
177236
</Grid.ColumnDefinitions>
178-
<Image Style="{StaticResource IconStyle}" VerticalAlignment="Top" Grid.Column="0"
237+
<Image Style="{StaticResource IconMargin}" VerticalAlignment="Top" Grid.Column="0"
179238
Source="{Binding SelectedItem.Inspection.Severity, Converter={StaticResource SeverityIconConverter}}"/>
180239
<TextBlock Grid.Column="1" Margin="4" Text="{Binding SelectedItem.Inspection.Description}" FontWeight="Bold" TextWrapping="WrapWithOverflow"/>
181240
</Grid>
@@ -199,7 +258,7 @@
199258
<controls:LinkButton Margin="4"
200259
Visibility="{Binding CanExecuteQuickFixInProject, Converter={StaticResource BoolToVisibility}}"
201260
Command="{Binding QuickFixInAllProjectsCommand}"
202-
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_AllOpenProjects}" />
261+
Content="{Resx ResxName=Rubberduck.Resources.Inspections.InspectionsUI, Key=QuickFix_All}" />
203262
<controls:LinkButton Margin="4"
204263
Visibility="{Binding CanDisableInspection, Converter={StaticResource BoolToVisibility}}"
205264
Command="{Binding DisableInspectionCommand}"

Rubberduck.Core/UI/Inspections/InspectionResultsViewModel.cs

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,14 @@ private void _configService_SettingsChanged(object sender, ConfigurationChangedE
117117
_runInspectionsOnReparse = e.RunInspectionsOnReparse;
118118
}
119119

120-
private ObservableCollection<IInspectionResult> _results = new ObservableCollection<IInspectionResult>();
120+
private ObservableCollection<IInspectionResult> _resultsAll = new ObservableCollection<IInspectionResult>();
121+
private ObservableCollection<IInspectionResult> _resultsGroupedAndFiltered = new ObservableCollection<IInspectionResult>();
121122
public ObservableCollection<IInspectionResult> Results
122123
{
123-
get => _results;
124+
get => _resultsGroupedAndFiltered;
124125
private set
125126
{
126-
_results = value;
127+
_resultsGroupedAndFiltered = value;
127128
OnPropertyChanged();
128129
}
129130
}
@@ -203,6 +204,7 @@ public bool GroupByInspectionType
203204
.ThenBy(t => t.QualifiedSelection.Selection.StartLine)
204205
.ThenBy(t => t.QualifiedSelection.Selection.StartColumn)
205206
.ToList());
207+
206208
}
207209

208210
_groupByInspectionType = value;
@@ -233,6 +235,85 @@ public bool GroupByLocation
233235
}
234236
}
235237

238+
private readonly List<CodeInspectionSeverity> _filterCriteria = new List<CodeInspectionSeverity>();
239+
240+
public bool FilterInspectionsByHint
241+
{
242+
get => _filterCriteria.Contains(CodeInspectionSeverity.Hint);
243+
set
244+
{
245+
UpdateFilterCriteria(value, CodeInspectionSeverity.Hint);
246+
247+
FilterResults(_filterCriteria);
248+
OnPropertyChanged();
249+
}
250+
}
251+
252+
public bool FilterInspectionsBySuggestion
253+
{
254+
get => _filterCriteria.Contains(CodeInspectionSeverity.Suggestion);
255+
set
256+
{
257+
UpdateFilterCriteria(value, CodeInspectionSeverity.Suggestion);
258+
259+
FilterResults(_filterCriteria);
260+
OnPropertyChanged();
261+
}
262+
}
263+
264+
public bool FilterInspectionsByWarning
265+
{
266+
get => _filterCriteria.Contains(CodeInspectionSeverity.Warning);
267+
set
268+
{
269+
UpdateFilterCriteria(value, CodeInspectionSeverity.Warning);
270+
271+
FilterResults(_filterCriteria);
272+
OnPropertyChanged();
273+
}
274+
}
275+
276+
public bool FilterInspectionsByError
277+
{
278+
get => _filterCriteria.Contains(CodeInspectionSeverity.Error);
279+
set
280+
{
281+
UpdateFilterCriteria(value, CodeInspectionSeverity.Error);
282+
283+
FilterResults(_filterCriteria);
284+
OnPropertyChanged();
285+
}
286+
}
287+
288+
private void UpdateFilterCriteria(bool isCriteria ,CodeInspectionSeverity criteria)
289+
{
290+
if (_filterCriteria.Contains(criteria) == isCriteria) { return; }
291+
292+
if (isCriteria)
293+
{
294+
_filterCriteria.Add(criteria);
295+
}
296+
else
297+
{
298+
_filterCriteria.Remove(criteria);
299+
}
300+
}
301+
302+
public void FilterResults(IEnumerable<CodeInspectionSeverity> inspections)
303+
{
304+
if (_filterCriteria.Any())
305+
{
306+
Results = new ObservableCollection<IInspectionResult>(_resultsAll
307+
.GroupBy(result => result.Inspection.Severity)
308+
.Where(group => _filterCriteria.Contains(group.Key))
309+
.SelectMany(x => x));
310+
}
311+
else
312+
{
313+
Results = _resultsAll;
314+
}
315+
}
316+
236317
public INavigateCommand NavigateCommand { get; }
237318
public CommandBase SetInspectionTypeGroupingCommand { get; }
238319
public CommandBase SetLocationGroupingCommand { get; }
@@ -339,7 +420,8 @@ private async void RefreshInspections(CancellationToken token)
339420
.ToList();
340421
}
341422

342-
Results = new ObservableCollection<IInspectionResult>(results);
423+
_resultsAll = new ObservableCollection<IInspectionResult>(results);
424+
Results = _resultsAll;
343425

344426
_uiDispatcher.Invoke(() =>
345427
{
@@ -502,21 +584,21 @@ private void ExecuteQuickFixInAllProjectsCommand(object parameter)
502584
private void ExecuteCopyResultsCommand(object parameter)
503585
{
504586
const string xmlSpreadsheetDataFormat = "XML Spreadsheet";
505-
if (_results == null)
587+
if (_resultsAll == null)
506588
{
507589
return;
508590
}
509591
ColumnInfo[] columnInfos = { new ColumnInfo("Type"), new ColumnInfo("Project"), new ColumnInfo("Component"), new ColumnInfo("Issue"), new ColumnInfo("Line", hAlignment.Right), new ColumnInfo("Column", hAlignment.Right) };
510592

511-
var resultArray = _results.OfType<IExportable>().Select(result => result.ToArray()).ToArray();
593+
var resultArray = _resultsAll.OfType<IExportable>().Select(result => result.ToArray()).ToArray();
512594

513-
var resource = _results.Count == 1
595+
var resource = _resultsAll.Count == 1
514596
? Resources.RubberduckUI.CodeInspections_NumberOfIssuesFound_Singular
515597
: Resources.RubberduckUI.CodeInspections_NumberOfIssuesFound_Plural;
516598

517-
var title = string.Format(resource, DateTime.Now.ToString(CultureInfo.InvariantCulture), _results.Count);
599+
var title = string.Format(resource, DateTime.Now.ToString(CultureInfo.InvariantCulture), _resultsAll.Count);
518600

519-
var textResults = title + Environment.NewLine + string.Join("", _results.OfType<IExportable>().Select(result => result.ToClipboardString() + Environment.NewLine).ToArray());
601+
var textResults = title + Environment.NewLine + string.Join("", _resultsAll.OfType<IExportable>().Select(result => result.ToClipboardString() + Environment.NewLine).ToArray());
520602
var csvResults = ExportFormatter.Csv(resultArray, title,columnInfos);
521603
var htmlResults = ExportFormatter.HtmlClipboardFragment(resultArray, title,columnInfos);
522604
var rtfResults = ExportFormatter.RTF(resultArray, title);
@@ -535,7 +617,7 @@ private void ExecuteCopyResultsCommand(object parameter)
535617

536618
private bool CanExecuteCopyResultsCommand(object parameter)
537619
{
538-
return !IsBusy && _results != null && _results.Any();
620+
return !IsBusy && _resultsAll != null && _resultsAll.Any();
539621
}
540622

541623
public Visibility EmptyUIRefreshVisibility => _state.Projects.Count > 0 ? Visibility.Hidden : Visibility.Visible;

Rubberduck.Core/UI/Settings/GeneralSettings.xaml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@
118118
</Label>
119119
<Label Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_LanguageLabel}" FontWeight="SemiBold" />
120120
<ComboBox Width="210"
121-
HorizontalAlignment="Left"
122-
Margin="5"
123-
SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}"
124-
ItemsSource="{Binding Languages, UpdateSourceTrigger=PropertyChanged}"
125-
DisplayMemberPath="Name" />
121+
HorizontalAlignment="Left"
122+
Margin="5"
123+
SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}"
124+
ItemsSource="{Binding Languages, UpdateSourceTrigger=PropertyChanged}"
125+
DisplayMemberPath="Name" />
126126

127127
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_ShowSplash}"
128128
IsChecked="{Binding ShowSplashAtStartup}" />
@@ -136,11 +136,11 @@
136136
<Label Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_MinimumLogLevelLabel}" FontWeight="SemiBold" />
137137
<StackPanel Orientation="Horizontal">
138138
<ComboBox Width="210"
139-
HorizontalAlignment="Left"
140-
Margin="5"
141-
SelectedItem="{Binding SelectedLogLevel, Mode=TwoWay}"
142-
ItemsSource="{Binding LogLevels, UpdateSourceTrigger=PropertyChanged}"
143-
DisplayMemberPath="Name"/>
139+
HorizontalAlignment="Left"
140+
Margin="5"
141+
SelectedItem="{Binding SelectedLogLevel, Mode=TwoWay}"
142+
ItemsSource="{Binding LogLevels, UpdateSourceTrigger=PropertyChanged}"
143+
DisplayMemberPath="Name"/>
144144
<Button
145145
Content="{Resx ResxName=Rubberduck.Resources.RubberduckUI, Key=GeneralSettings_ShowLogFolder}"
146146
Padding="5"

0 commit comments

Comments
 (0)