Skip to content

Commit c5da161

Browse files
committed
Add basic UI for CodeMetrics
1 parent 2542c6b commit c5da161

14 files changed

+776
-7
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using NLog;
2+
using Rubberduck.Parsing.VBA;
3+
using Rubberduck.UI;
4+
using Rubberduck.UI.Command;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
9+
namespace Rubberduck.Navigation.CodeMetrics
10+
{
11+
public class CodeMetricsViewModel : ViewModelBase
12+
{
13+
private readonly RubberduckParserState _state;
14+
15+
public CodeMetricsViewModel(RubberduckParserState state, List<CommandBase> commands, ICodeMetricsAnalyst analyst)
16+
17+
{
18+
_state = state;
19+
var reparseCommand = commands.OfType<ReparseCommand>().SingleOrDefault();
20+
RefreshCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(),
21+
reparseCommand == null ? (Action<object>)(o => { }) :
22+
o => reparseCommand.Execute(o),
23+
o => !IsBusy && reparseCommand != null && reparseCommand.CanExecute(o));
24+
25+
_state.StateChanged += (_, change) =>
26+
{
27+
if (change.State == ParserState.Ready)
28+
{
29+
ModuleMetrics = analyst.ModuleMetrics(_state);
30+
}
31+
};
32+
}
33+
34+
public void FilterByName(object projects, string text)
35+
{
36+
throw new NotImplementedException();
37+
}
38+
39+
private IEnumerable<ModuleMetricsResult> _moduleMetrics;
40+
public IEnumerable<ModuleMetricsResult> ModuleMetrics {
41+
get => _moduleMetrics;
42+
private set
43+
{
44+
_moduleMetrics = value;
45+
OnPropertyChanged();
46+
}
47+
}
48+
49+
50+
public CommandBase RefreshCommand { get; set; }
51+
52+
53+
private bool _canSearch;
54+
public bool CanSearch
55+
{
56+
get => _canSearch;
57+
set
58+
{
59+
_canSearch = value;
60+
OnPropertyChanged();
61+
}
62+
}
63+
64+
private bool _isBusy;
65+
public bool IsBusy
66+
{
67+
get => _isBusy;
68+
set
69+
{
70+
_isBusy = value;
71+
OnPropertyChanged();
72+
// If the window is "busy" then hide the Refresh message
73+
OnPropertyChanged("EmptyUIRefreshMessageVisibility");
74+
}
75+
}
76+
}
77+
}

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@
346346
<Compile Include="Navigation\CodeExplorer\ICodeExplorerDeclarationViewModel.cs" />
347347
<Compile Include="Navigation\CodeMetrics\CodeMetricsAnalyst.cs" />
348348
<Compile Include="Navigation\CodeMetrics\CodeMetricsResult.cs" />
349+
<Compile Include="Navigation\CodeMetrics\CodeMetricsViewModel.cs" />
349350
<Compile Include="Navigation\CodeMetrics\ICodeMetricsAnalyst.cs" />
350351
<Compile Include="Navigation\Folders\FolderHelper.cs" />
351352
<Compile Include="Refactorings\EncapsulateField\PropertyGenerator.cs" />
@@ -389,8 +390,20 @@
389390
<Compile Include="UI\CodeExplorer\Commands\CommitCommand.cs" />
390391
<Compile Include="UI\CodeExplorer\Commands\AddUserFormCommand.cs" />
391392
<Compile Include="UI\CodeExplorer\Commands\CopyResultsCommand.cs" />
392-
<Compile Include="UI\CodeExplorer\Converters\StringHasNoValueToVisibilityConverter.cs" />
393-
<Compile Include="UI\CodeExplorer\Converters\StringHasValueToVisibilityConverter.cs" />
393+
<Compile Include="UI\CodeMetrics\CodeMetricsWindow.cs">
394+
<SubType>UserControl</SubType>
395+
</Compile>
396+
<Compile Include="UI\CodeMetrics\CodeMetricsWindow.Designer.cs">
397+
<DependentUpon>CodeMetricsWindow.cs</DependentUpon>
398+
</Compile>
399+
<Compile Include="UI\CodeMetrics\CodeMetricsDockablePresenter.cs" />
400+
<Compile Include="UI\Command\CodeMetricsCommand.cs" />
401+
<Compile Include="UI\Command\MenuItems\CodeMetricsCommandMenuItem.cs" />
402+
<Compile Include="UI\Converters\StringHasNoValueToVisibilityConverter.cs" />
403+
<Compile Include="UI\Converters\StringHasValueToVisibilityConverter.cs" />
404+
<Compile Include="UI\CodeMetrics\CodeMetricsControl.xaml.cs">
405+
<DependentUpon>CodeMetricsControl.xaml</DependentUpon>
406+
</Compile>
394407
<Compile Include="UI\Command\ExportAllCommand.cs" />
395408
<Compile Include="UI\CodeExplorer\Commands\OpenProjectPropertiesCommand.cs" />
396409
<Compile Include="UI\CodeExplorer\Commands\RenameCommand.cs" />
@@ -972,6 +985,9 @@
972985
<SubType>Designer</SubType>
973986
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
974987
</EmbeddedResource>
988+
<EmbeddedResource Include="UI\CodeMetrics\CodeMetricsWindow.resx">
989+
<DependentUpon>CodeMetricsWindow.cs</DependentUpon>
990+
</EmbeddedResource>
975991
<EmbeddedResource Include="UI\Inspections\InspectionResultsWindow.resx">
976992
<DependentUpon>InspectionResultsWindow.cs</DependentUpon>
977993
</EmbeddedResource>
@@ -1359,6 +1375,10 @@
13591375
<SubType>Designer</SubType>
13601376
<Generator>MSBuild:Compile</Generator>
13611377
</Page>
1378+
<Page Include="UI\CodeMetrics\CodeMetricsControl.xaml">
1379+
<Generator>MSBuild:Compile</Generator>
1380+
<SubType>Designer</SubType>
1381+
</Page>
13621382
<Page Include="UI\Controls\GroupingGrid.xaml">
13631383
<SubType>Designer</SubType>
13641384
<Generator>MSBuild:Compile</Generator>

RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
xmlns:controls="clr-namespace:Rubberduck.UI.Controls"
99
xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
1010
xmlns:converters="clr-namespace:Rubberduck.UI.Converters"
11-
xmlns:codeExplorerConverters="clr-namespace:Rubberduck.UI.CodeExplorer.Converters"
1211
ResxExtension.DefaultResxName="Rubberduck.UI.RubberduckUI"
1312
Language="{UICulture}"
1413
Name="CodeExplorer"
@@ -33,8 +32,8 @@
3332

3433
<BooleanToVisibilityConverter x:Key="BoolToVisibility"/>
3534
<converters:BoolToHiddenVisibilityConverter x:Key="BoolToHiddenVisibility" />
36-
<codeExplorerConverters:StringHasValueToVisibilityConverter x:Key="StringHasValueToVisibility" />
37-
<codeExplorerConverters:StringHasNoValueToVisibilityConverter x:Key="StringHasNoValueToVisibility" />
35+
<converters:StringHasValueToVisibilityConverter x:Key="StringHasValueToVisibility" />
36+
<converters:StringHasNoValueToVisibilityConverter x:Key="StringHasNoValueToVisibility" />
3837

3938
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
4039
<GradientStop Color="#FFD9F4FF" Offset="0"/>
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<UserControl x:Class="Rubberduck.UI.CodeMetrics.CodeMetricsControl"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
7+
xmlns:codeMetrics="clr-namespace:Rubberduck.Navigation.CodeMetrics"
8+
xmlns:controls="clr-namespace:Rubberduck.UI.Controls"
9+
xmlns:converters="clr-namespace:Rubberduck.UI.Converters"
10+
ResxExtension.DefaultResxName="Rubberduck.UI.RubberduckUI"
11+
Language="{UICulture}"
12+
Name="CodeMetrics"
13+
mc:Ignorable="d"
14+
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance codeMetrics:CodeMetricsViewModel}">
15+
<UserControl.Resources>
16+
<ResourceDictionary>
17+
<ResourceDictionary.MergedDictionaries>
18+
<ResourceDictionary Source="../Controls/ToolBar.xaml"/>
19+
</ResourceDictionary.MergedDictionaries>
20+
21+
<BitmapImage x:Key="RefreshImage" UriSource="../../Resources/arrow-circle-double.png" />
22+
<BitmapImage x:Key="CollaseNodesImage" UriSource="../../Resources/folder.png" />
23+
<BitmapImage x:Key="ExpandNodesImage" UriSource="../../Resources/folder-open.png" />
24+
<BitmapImage x:Key="UndoImage" UriSource="../../Resources/arrow-circle-left.png" />
25+
<BitmapImage x:Key="PrintImage" UriSource="../../Resources/printer.png" />
26+
<BitmapImage x:Key="SearchImage" UriSource="../../Resources/magnifier-medium.png" />
27+
28+
<BooleanToVisibilityConverter x:Key="BoolToVisibility"/>
29+
<converters:BoolToHiddenVisibilityConverter x:Key="BoolToHiddenVisibility" />
30+
<converters:StringHasValueToVisibilityConverter x:Key="StringHasValueToVisibility" />
31+
<converters:StringHasNoValueToVisibilityConverter x:Key="StringHasNoValueToVisibility" />
32+
33+
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
34+
<GradientStop Color="#FFD9F4FF" Offset="0"/>
35+
<GradientStop Color="#FF9BDDFB" Offset="1"/>
36+
</LinearGradientBrush>
37+
<LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0">
38+
<GradientStop Color="#FFEEEDED" Offset="0"/>
39+
<GradientStop Color="#FFDDDDDD" Offset="1"/>
40+
</LinearGradientBrush>
41+
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
42+
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
43+
44+
<Style x:Key="XButtonStyle" TargetType="Button">
45+
<Setter Property="Background" Value="Transparent"/>
46+
<Setter Property="Content" Value=""/>
47+
<Setter Property="BorderThickness" Value="0"/>
48+
<Setter Property="HorizontalContentAlignment" Value="Center"/>
49+
<Setter Property="VerticalContentAlignment" Value="Center"/>
50+
<Setter Property="Template">
51+
<Setter.Value>
52+
<ControlTemplate TargetType="Button">
53+
<Grid>
54+
<VisualStateManager.VisualStateGroups>
55+
<VisualStateGroup x:Name="CommonStates">
56+
<VisualState x:Name="Normal"/>
57+
<VisualState x:Name="MouseOver">
58+
<Storyboard>
59+
<ColorAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="PaleGoldenrod"/>
60+
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
61+
</Storyboard>
62+
</VisualState>
63+
<VisualState x:Name="Pressed">
64+
<Storyboard>
65+
<ColorAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="PaleGoldenrod"/>
66+
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
67+
</Storyboard>
68+
</VisualState>
69+
</VisualStateGroup>
70+
<VisualStateGroup x:Name="FocusStates">
71+
<VisualState x:Name="Focused">
72+
<Storyboard>
73+
<DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1"/>
74+
</Storyboard>
75+
</VisualState>
76+
<VisualState x:Name="Unfocused" />
77+
</VisualStateGroup>
78+
</VisualStateManager.VisualStateGroups>
79+
<Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
80+
<Grid Background="{TemplateBinding Background}" Margin="1">
81+
<Border Opacity="0" x:Name="BackgroundAnimation" Background="PaleGoldenrod" />
82+
</Grid>
83+
</Border>
84+
<ContentPresenter
85+
x:Name="contentPresenter"
86+
Content="{TemplateBinding Content}"
87+
ContentTemplate="{TemplateBinding ContentTemplate}"
88+
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
89+
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
90+
Margin="{TemplateBinding Padding}"/>
91+
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
92+
<Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="PaleGoldenrod" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
93+
</Grid>
94+
</ControlTemplate>
95+
</Setter.Value>
96+
</Setter>
97+
</Style>
98+
</ResourceDictionary>
99+
</UserControl.Resources>
100+
101+
<Grid UseLayoutRounding="True">
102+
<Grid.RowDefinitions>
103+
<RowDefinition Height="30"/>
104+
<RowDefinition Height="20"/>
105+
<RowDefinition Height="*" MinHeight="64" />
106+
</Grid.RowDefinitions>
107+
108+
<ToolBarTray Grid.Row="0" IsLocked="True">
109+
<ToolBar Style="{DynamicResource ToolBarWithOverflowOnlyShowingWhenNeededStyle}">
110+
111+
<Button Command="{Binding RefreshCommand}">
112+
<Image Height="16" Source="../../Resources/arrow-circle-double.png">
113+
<Image.Style>
114+
<Style TargetType="Image">
115+
<Style.Triggers>
116+
<Trigger Property="IsEnabled" Value="False">
117+
<Setter Property="Opacity" Value="0.3" />
118+
</Trigger>
119+
</Style.Triggers>
120+
</Style>
121+
</Image.Style>
122+
</Image>
123+
<Button.ToolTip>
124+
<TextBlock Text="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=Refresh}" />
125+
</Button.ToolTip>
126+
</Button>
127+
</ToolBar>
128+
</ToolBarTray>
129+
130+
<Border Grid.Row="1"
131+
BorderBrush="{StaticResource {x:Static SystemColors.ControlBrushKey}}"
132+
BorderThickness="1">
133+
<Grid>
134+
<TextBox x:Name="SearchBox"
135+
VerticalContentAlignment="Center"
136+
IsEnabled="{Binding CanSearch}"
137+
MinHeight="20"
138+
PreviewKeyDown="SearchBox_OnPreviewKeyDown"
139+
TextChanged="SearchBox_OnTextChanged" />
140+
141+
<Image Source="{StaticResource SearchImage}"
142+
HorizontalAlignment="Right" VerticalAlignment="Center"
143+
MaxHeight="16" Margin="0,0,1,0"
144+
IsEnabled="{Binding CanSearch}"
145+
Visibility="{Binding ElementName=SearchBox, Path=Text.Length, Converter={StaticResource StringHasValueToVisibility}}"
146+
MouseDown="SearchIcon_OnMouseDown" />
147+
148+
<Button Style="{StaticResource XButtonStyle}"
149+
HorizontalAlignment="Right" VerticalAlignment="Center"
150+
Height="18" Width="18" Margin="0,1,1,0"
151+
IsEnabled="{Binding CanSearch}"
152+
Visibility="{Binding ElementName=SearchBox, Path=Text.Length, Converter={StaticResource StringHasNoValueToVisibility}}"
153+
Click="ButtonBase_OnClick" />
154+
</Grid>
155+
</Border>
156+
<controls:EmptyUIRefresh Grid.Row="2" />
157+
158+
<TreeView ItemsSource="{Binding ModuleMetrics}" Grid.Row="2" >
159+
<TreeView.ItemTemplate>
160+
<HierarchicalDataTemplate>
161+
<Grid>
162+
<TextBlock Grid.Column="0" Text="{Binding Path=ModuleName}"/>
163+
<TextBlock Grid.Column="1" Text="{Binding Path=Result.Lines}" />
164+
<TextBlock Grid.Column="2" Text="{Binding Path=Result.CyclomaticComplexity}" />
165+
<TextBlock Grid.Column="3" Text="{Binding Path=Result.MaximumNesting}" />
166+
</Grid>
167+
<HierarchicalDataTemplate.ItemTemplate ItemsSource="{Binding MemberResults}">
168+
<DataTemplate>
169+
<Grid>
170+
<TextBlock Grid.Column="0" Text="{Binding Path=Key}"/>
171+
<TextBlock Grid.Column="1" Text="{Binding Path=Value.Lines}" />
172+
<TextBlock Grid.Column="2" Text="{Binding Path=Value.CyclomaticComplexity}" />
173+
<TextBlock Grid.Column="3" Text="{Binding Path=Value.MaximumNesting}" />
174+
</Grid>
175+
</DataTemplate>
176+
</HierarchicalDataTemplate.ItemTemplate>
177+
</HierarchicalDataTemplate>
178+
</TreeView.ItemTemplate>
179+
</TreeView>
180+
<controls:BusyIndicator Grid.Row="2" Width="120" Height="120" Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibility}}" />
181+
</Grid>
182+
</UserControl>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Windows;
2+
using System.Windows.Controls;
3+
using System.Windows.Input;
4+
using Rubberduck.Navigation.CodeMetrics;
5+
6+
namespace Rubberduck.UI.CodeMetrics
7+
{
8+
/// <summary>
9+
/// Interaction logic for CodeMetricsControl.xaml
10+
/// </summary>
11+
public partial class CodeMetricsControl
12+
{
13+
public CodeMetricsControl()
14+
{
15+
InitializeComponent();
16+
}
17+
18+
private CodeMetricsViewModel ViewModel { get { return DataContext as CodeMetricsViewModel; } }
19+
private void SearchBox_OnTextChanged(object sender, TextChangedEventArgs e)
20+
{
21+
ViewModel.FilterByName(ViewModel.ModuleMetrics, ((TextBox)sender).Text);
22+
}
23+
24+
private void SearchIcon_OnMouseDown(object sender, MouseButtonEventArgs e)
25+
{
26+
SearchBox.Focus();
27+
}
28+
29+
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
30+
{
31+
ClearSearchBox();
32+
}
33+
34+
private void ClearSearchBox()
35+
{
36+
SearchBox.Text = string.Empty;
37+
SearchBox.Focus();
38+
}
39+
40+
private void SearchBox_OnPreviewKeyDown(object sender, KeyEventArgs e)
41+
{
42+
if (e.Key == Key.Escape)
43+
{
44+
ClearSearchBox();
45+
}
46+
}
47+
}
48+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Rubberduck.Settings;
2+
using Rubberduck.SettingsProvider;
3+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
4+
5+
namespace Rubberduck.UI.CodeMetrics
6+
{
7+
public class CodeMetricsDockablePresenter : DockableToolwindowPresenter
8+
{
9+
public CodeMetricsDockablePresenter(IVBE vbe, IAddIn addIn, CodeMetricsWindow view, IConfigProvider<WindowSettings> settings)
10+
: base(vbe, addIn, view, settings)
11+
{
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)