Skip to content

Commit f0d4885

Browse files
authored
Merge pull request #4661 from comintern/refs
Code Explorer Extreme Makeover (for some values of extreme)
2 parents a926409 + 6df5bde commit f0d4885

File tree

92 files changed

+6076
-3289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+6076
-3289
lines changed

Rubberduck.Core/CodeAnalysis/CodeMetrics/CodeMetricsViewModel.cs

Lines changed: 68 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -6,136 +6,93 @@
66
using System.Collections.Generic;
77
using System.Collections.ObjectModel;
88
using Rubberduck.Navigation.CodeExplorer;
9-
using System.Windows;
10-
using Rubberduck.Navigation.Folders;
9+
using Rubberduck.Parsing.UIContext;
1110
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1211

1312
namespace Rubberduck.CodeAnalysis.CodeMetrics
1413
{
15-
public class CodeMetricsViewModel : ViewModelBase, IDisposable
14+
public sealed class CodeMetricsViewModel : ViewModelBase, IDisposable
1615
{
1716
private readonly RubberduckParserState _state;
1817
private readonly ICodeMetricsAnalyst _analyst;
19-
private readonly FolderHelper _folderHelper;
2018
private readonly IVBE _vbe;
19+
private readonly IUiDispatcher _uiDispatcher;
2120

22-
public CodeMetricsViewModel(RubberduckParserState state, ICodeMetricsAnalyst analyst, FolderHelper folderHelper, IVBE vbe)
21+
public CodeMetricsViewModel(
22+
RubberduckParserState state,
23+
ICodeMetricsAnalyst analyst,
24+
IVBE vbe,
25+
IUiDispatcher uiDispatcher)
2326
{
2427
_state = state;
25-
_analyst = analyst;
26-
_folderHelper = folderHelper;
2728
_state.StateChanged += OnStateChanged;
29+
30+
_analyst = analyst;
2831
_vbe = vbe;
29-
}
30-
31-
private void OnStateChanged(object sender, ParserStateEventArgs e)
32-
{
33-
if (e.State != ParserState.Ready && e.State != ParserState.Error && e.State != ParserState.ResolverError && e.State != ParserState.UnexpectedError)
34-
{
35-
IsBusy = true;
36-
}
32+
_uiDispatcher = uiDispatcher;
3733

38-
if (e.State == ParserState.Ready)
39-
{
40-
UpdateData();
41-
IsBusy = false;
42-
}
34+
OnPropertyChanged(nameof(Projects));
35+
}
4336

44-
if (e.State == ParserState.Error || e.State == ParserState.ResolverError || e.State == ParserState.UnexpectedError)
37+
private bool _unparsed = true;
38+
public bool Unparsed
39+
{
40+
get => _unparsed;
41+
set
4542
{
46-
IsBusy = false;
43+
if (_unparsed == value)
44+
{
45+
return;
46+
}
47+
_unparsed = value;
48+
OnPropertyChanged();
4749
}
4850
}
4951

50-
private void UpdateData()
52+
private void OnStateChanged(object sender, ParserStateEventArgs e)
5153
{
52-
IsBusy = true;
53-
54-
var metricResults = _analyst.GetMetrics(_state);
55-
resultsByDeclaration = metricResults.GroupBy(r => r.Declaration).ToDictionary(g => g.Key, g => g.ToList());
54+
Unparsed = false;
55+
IsBusy = _state.Status != ParserState.Pending && _state.Status <= ParserState.ResolvedDeclarations;
5656

57-
if (Projects == null)
57+
if (e.State != ParserState.ResolvedDeclarations)
5858
{
59-
Projects = new ObservableCollection<CodeExplorerItemViewModel>();
59+
return;
6060
}
6161

62-
IsBusy = _state.Status != ParserState.Pending && _state.Status <= ParserState.ResolvedDeclarations;
63-
64-
var userDeclarations = _state.DeclarationFinder.AllUserDeclarations
65-
.GroupBy(declaration => declaration.ProjectId)
66-
.ToList();
67-
68-
var newProjects = userDeclarations
69-
.Where(grouping => grouping.Any(declaration => declaration.DeclarationType == DeclarationType.Project))
70-
.Select(grouping =>
71-
new CodeExplorerProjectViewModel(_folderHelper,
72-
grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project),
73-
grouping,
74-
_vbe)).ToList();
75-
76-
UpdateNodes(Projects, newProjects);
77-
78-
Projects = new ObservableCollection<CodeExplorerItemViewModel>(newProjects);
79-
80-
IsBusy = false;
62+
Synchronize(_state.DeclarationFinder.AllUserDeclarations.ToList());
8163
}
8264

83-
private void UpdateNodes(IEnumerable<CodeExplorerItemViewModel> oldList, IEnumerable<CodeExplorerItemViewModel> newList)
65+
private void Synchronize(List<Declaration> declarations)
8466
{
85-
foreach (var item in newList)
86-
{
87-
CodeExplorerItemViewModel oldItem;
67+
var metricResults = _analyst.GetMetrics(_state);
68+
_resultsByDeclaration = metricResults.GroupBy(r => r.Declaration).ToDictionary(g => g.Key, g => g.ToList());
8869

89-
if (item is CodeExplorerCustomFolderViewModel)
90-
{
91-
oldItem = oldList.FirstOrDefault(i => i.Name == item.Name);
92-
}
93-
else
94-
{
95-
oldItem = oldList.FirstOrDefault(i =>
96-
item.QualifiedSelection != null && i.QualifiedSelection != null &&
97-
i.QualifiedSelection.Value.QualifiedName.ProjectId ==
98-
item.QualifiedSelection.Value.QualifiedName.ProjectId &&
99-
i.QualifiedSelection.Value.QualifiedName.ComponentName ==
100-
item.QualifiedSelection.Value.QualifiedName.ComponentName &&
101-
i.QualifiedSelection.Value.Selection == item.QualifiedSelection.Value.Selection);
102-
}
70+
_uiDispatcher.Invoke(() =>
71+
{
72+
var existing = Projects.OfType<CodeExplorerProjectViewModel>().ToList();
10373

104-
if (oldItem != null)
74+
foreach (var project in existing)
10575
{
106-
item.IsExpanded = oldItem.IsExpanded;
107-
item.IsSelected = oldItem.IsSelected;
108-
109-
if (oldItem.Items.Any() && item.Items.Any())
76+
project.Synchronize(declarations);
77+
if (project.Declaration is null)
11078
{
111-
UpdateNodes(oldItem.Items, item.Items);
79+
Projects.Remove(project);
11280
}
11381
}
114-
}
115-
}
116-
117-
public void Dispose()
118-
{
119-
Dispose(true);
120-
GC.SuppressFinalize(this);
121-
}
12282

123-
private bool _isDisposed;
124-
protected virtual void Dispose(bool disposing)
125-
{
126-
if (_isDisposed || !disposing)
127-
{
128-
return;
129-
}
130-
_isDisposed = true;
83+
var adding = declarations.OfType<ProjectDeclaration>().ToList();
13184

132-
_state.StateChanged -= OnStateChanged;
85+
foreach (var project in adding)
86+
{
87+
var model = new CodeExplorerProjectViewModel(project, declarations, _state, _vbe, false);
88+
Projects.Add(model);
89+
model.IsExpanded = true;
90+
}
91+
});
13392
}
13493

135-
private Dictionary<Declaration, List<ICodeMetricResult>> resultsByDeclaration;
136-
137-
private CodeExplorerItemViewModel _selectedItem;
138-
public CodeExplorerItemViewModel SelectedItem
94+
private ICodeExplorerNode _selectedItem;
95+
public ICodeExplorerNode SelectedItem
13996
{
14097
get => _selectedItem;
14198
set
@@ -150,27 +107,15 @@ public CodeExplorerItemViewModel SelectedItem
150107
}
151108
}
152109

153-
private ObservableCollection<CodeExplorerItemViewModel> _projects;
154-
public ObservableCollection<CodeExplorerItemViewModel> Projects
155-
{
156-
get => _projects;
157-
set
158-
{
159-
_projects = new ObservableCollection<CodeExplorerItemViewModel>(value.OrderBy(o => o.NameWithSignature));
110+
public ObservableCollection<ICodeExplorerNode> Projects { get; } = new ObservableCollection<ICodeExplorerNode>();
160111

161-
OnPropertyChanged();
162-
OnPropertyChanged(nameof(TreeViewVisibility));
163-
}
164-
}
165-
166-
public Visibility TreeViewVisibility => Projects == null || Projects.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
167-
112+
private Dictionary<Declaration, List<ICodeMetricResult>> _resultsByDeclaration;
168113
public ObservableCollection<ICodeMetricResult> Metrics
169114
{
170115
get
171116
{
172-
var results = resultsByDeclaration?.FirstOrDefault(f => f.Key == SelectedItem.GetSelectedDeclaration());
173-
return !results.HasValue || results.Value.Value == null ? new ObservableCollection<ICodeMetricResult>() : new ObservableCollection<ICodeMetricResult>(results.Value.Value);
117+
var results = _resultsByDeclaration?.FirstOrDefault(f => ReferenceEquals(f.Key, SelectedItem.Declaration));
118+
return results?.Value == null ? new ObservableCollection<ICodeMetricResult>() : new ObservableCollection<ICodeMetricResult>(results.Value.Value);
174119
}
175120
}
176121

@@ -181,23 +126,27 @@ public bool IsBusy
181126
set
182127
{
183128
_isBusy = value;
184-
EmptyUIRefreshMessageVisibility = false;
185129
OnPropertyChanged();
186130
}
187131
}
188132

189-
private bool _emptyUIRefreshMessageVisibility = true;
190-
public bool EmptyUIRefreshMessageVisibility
133+
public void Dispose()
191134
{
192-
get => _emptyUIRefreshMessageVisibility;
193-
set
135+
Dispose(true);
136+
GC.SuppressFinalize(this);
137+
}
138+
139+
private bool _isDisposed;
140+
141+
private void Dispose(bool disposing)
142+
{
143+
if (_isDisposed || !disposing)
194144
{
195-
if (_emptyUIRefreshMessageVisibility != value)
196-
{
197-
_emptyUIRefreshMessageVisibility = value;
198-
OnPropertyChanged();
199-
}
145+
return;
200146
}
147+
_isDisposed = true;
148+
149+
_state.StateChanged -= OnStateChanged;
201150
}
202151
}
203152
}

0 commit comments

Comments
 (0)