6
6
using System . Collections . Generic ;
7
7
using System . Collections . ObjectModel ;
8
8
using Rubberduck . Navigation . CodeExplorer ;
9
- using System . Windows ;
10
- using Rubberduck . Navigation . Folders ;
9
+ using Rubberduck . Parsing . UIContext ;
11
10
using Rubberduck . VBEditor . SafeComWrappers . Abstract ;
12
11
13
12
namespace Rubberduck . CodeAnalysis . CodeMetrics
14
13
{
15
- public class CodeMetricsViewModel : ViewModelBase , IDisposable
14
+ public sealed class CodeMetricsViewModel : ViewModelBase , IDisposable
16
15
{
17
16
private readonly RubberduckParserState _state ;
18
17
private readonly ICodeMetricsAnalyst _analyst ;
19
- private readonly FolderHelper _folderHelper ;
20
18
private readonly IVBE _vbe ;
19
+ private readonly IUiDispatcher _uiDispatcher ;
21
20
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 )
23
26
{
24
27
_state = state ;
25
- _analyst = analyst ;
26
- _folderHelper = folderHelper ;
27
28
_state . StateChanged += OnStateChanged ;
29
+
30
+ _analyst = analyst ;
28
31
_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 ;
37
33
38
- if ( e . State == ParserState . Ready )
39
- {
40
- UpdateData ( ) ;
41
- IsBusy = false ;
42
- }
34
+ OnPropertyChanged ( nameof ( Projects ) ) ;
35
+ }
43
36
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
45
42
{
46
- IsBusy = false ;
43
+ if ( _unparsed == value )
44
+ {
45
+ return ;
46
+ }
47
+ _unparsed = value ;
48
+ OnPropertyChanged ( ) ;
47
49
}
48
50
}
49
51
50
- private void UpdateData ( )
52
+ private void OnStateChanged ( object sender , ParserStateEventArgs e )
51
53
{
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 ;
56
56
57
- if ( Projects == null )
57
+ if ( e . State == ParserState . ResolvedDeclarations )
58
58
{
59
- Projects = new ObservableCollection < CodeExplorerItemViewModel > ( ) ;
59
+ Synchronize ( _state . DeclarationFinder . AllUserDeclarations ) ;
60
60
}
61
-
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 ;
81
61
}
82
62
83
- private void UpdateNodes ( IEnumerable < CodeExplorerItemViewModel > oldList , IEnumerable < CodeExplorerItemViewModel > newList )
63
+ private void Synchronize ( IEnumerable < Declaration > declarations )
84
64
{
85
- foreach ( var item in newList )
86
- {
87
- CodeExplorerItemViewModel oldItem ;
65
+ var metricResults = _analyst . GetMetrics ( _state ) ;
66
+ _resultsByDeclaration = metricResults . GroupBy ( r => r . Declaration ) . ToDictionary ( g => g . Key , g => g . ToList ( ) ) ;
88
67
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
- }
68
+ _uiDispatcher . Invoke ( ( ) =>
69
+ {
70
+ var updates = declarations . ToList ( ) ;
71
+ var existing = Projects . OfType < CodeExplorerProjectViewModel > ( ) . ToList ( ) ;
103
72
104
- if ( oldItem != null )
73
+ foreach ( var project in existing )
105
74
{
106
- item . IsExpanded = oldItem . IsExpanded ;
107
- item . IsSelected = oldItem . IsSelected ;
108
-
109
- if ( oldItem . Items . Any ( ) && item . Items . Any ( ) )
75
+ project . Synchronize ( ref updates ) ;
76
+ if ( project . Declaration is null )
110
77
{
111
- UpdateNodes ( oldItem . Items , item . Items ) ;
78
+ Projects . Remove ( project ) ;
112
79
}
113
80
}
114
- }
115
- }
116
-
117
- public void Dispose ( )
118
- {
119
- Dispose ( true ) ;
120
- GC . SuppressFinalize ( this ) ;
121
- }
122
81
123
- private bool _isDisposed ;
124
- protected virtual void Dispose ( bool disposing )
125
- {
126
- if ( _isDisposed || ! disposing )
127
- {
128
- return ;
129
- }
130
- _isDisposed = true ;
82
+ var adding = updates . OfType < ProjectDeclaration > ( ) . ToList ( ) ;
131
83
132
- _state . StateChanged -= OnStateChanged ;
84
+ foreach ( var project in adding )
85
+ {
86
+ var model = new CodeExplorerProjectViewModel ( project , ref updates , _state , _vbe , false ) ;
87
+ Projects . Add ( model ) ;
88
+ }
89
+ } ) ;
133
90
}
134
91
135
- private Dictionary < Declaration , List < ICodeMetricResult > > resultsByDeclaration ;
136
-
137
- private CodeExplorerItemViewModel _selectedItem ;
138
- public CodeExplorerItemViewModel SelectedItem
92
+ private ICodeExplorerNode _selectedItem ;
93
+ public ICodeExplorerNode SelectedItem
139
94
{
140
95
get => _selectedItem ;
141
96
set
@@ -150,27 +105,15 @@ public CodeExplorerItemViewModel SelectedItem
150
105
}
151
106
}
152
107
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 ) ) ;
108
+ public ObservableCollection < ICodeExplorerNode > Projects { get ; } = new ObservableCollection < ICodeExplorerNode > ( ) ;
160
109
161
- OnPropertyChanged ( ) ;
162
- OnPropertyChanged ( nameof ( TreeViewVisibility ) ) ;
163
- }
164
- }
165
-
166
- public Visibility TreeViewVisibility => Projects == null || Projects . Count == 0 ? Visibility . Collapsed : Visibility . Visible ;
167
-
110
+ private Dictionary < Declaration , List < ICodeMetricResult > > _resultsByDeclaration ;
168
111
public ObservableCollection < ICodeMetricResult > Metrics
169
112
{
170
113
get
171
114
{
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 ) ;
115
+ var results = _resultsByDeclaration ? . FirstOrDefault ( f => ReferenceEquals ( f . Key , SelectedItem . Declaration ) ) ;
116
+ return results ? . Value == null ? new ObservableCollection < ICodeMetricResult > ( ) : new ObservableCollection < ICodeMetricResult > ( results . Value . Value ) ;
174
117
}
175
118
}
176
119
@@ -181,23 +124,27 @@ public bool IsBusy
181
124
set
182
125
{
183
126
_isBusy = value ;
184
- EmptyUIRefreshMessageVisibility = false ;
185
127
OnPropertyChanged ( ) ;
186
128
}
187
129
}
188
130
189
- private bool _emptyUIRefreshMessageVisibility = true ;
190
- public bool EmptyUIRefreshMessageVisibility
131
+ public void Dispose ( )
191
132
{
192
- get => _emptyUIRefreshMessageVisibility ;
193
- set
133
+ Dispose ( true ) ;
134
+ GC . SuppressFinalize ( this ) ;
135
+ }
136
+
137
+ private bool _isDisposed ;
138
+
139
+ private void Dispose ( bool disposing )
140
+ {
141
+ if ( _isDisposed || ! disposing )
194
142
{
195
- if ( _emptyUIRefreshMessageVisibility != value )
196
- {
197
- _emptyUIRefreshMessageVisibility = value ;
198
- OnPropertyChanged ( ) ;
199
- }
143
+ return ;
200
144
}
145
+ _isDisposed = true ;
146
+
147
+ _state . StateChanged -= OnStateChanged ;
201
148
}
202
149
}
203
150
}
0 commit comments