Skip to content

Commit 0a22f25

Browse files
committed
Code Explorer performance rewrite.
1 parent b6aa90c commit 0a22f25

40 files changed

+1909
-1668
lines changed

Rubberduck.Core/CodeAnalysis/CodeMetrics/CodeMetricsViewModel.cs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ public class CodeMetricsViewModel : ViewModelBase, IDisposable
1616
{
1717
private readonly RubberduckParserState _state;
1818
private readonly ICodeMetricsAnalyst _analyst;
19-
private readonly FolderHelper _folderHelper;
19+
//private readonly FolderHelper _folderHelper;
2020
private readonly IVBE _vbe;
2121

22-
public CodeMetricsViewModel(RubberduckParserState state, ICodeMetricsAnalyst analyst, FolderHelper folderHelper, IVBE vbe)
22+
public CodeMetricsViewModel(
23+
RubberduckParserState state,
24+
ICodeMetricsAnalyst analyst,
25+
//FolderHelper folderHelper,
26+
IVBE vbe)
2327
{
2428
_state = state;
2529
_analyst = analyst;
26-
_folderHelper = folderHelper;
30+
//_folderHelper = folderHelper;
2731
_state.StateChanged += OnStateChanged;
2832
_vbe = vbe;
2933
}
@@ -65,17 +69,17 @@ private void UpdateData()
6569
.GroupBy(declaration => declaration.ProjectId)
6670
.ToList();
6771

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();
72+
//var newProjects = userDeclarations
73+
// .Where(grouping => grouping.Any(declaration => declaration.DeclarationType == DeclarationType.Project))
74+
// .Select(grouping =>
75+
// new CodeExplorerProjectViewModel(_folderHelper,
76+
// grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project),
77+
// grouping,
78+
// _vbe)).ToList();
7579

76-
UpdateNodes(Projects, newProjects);
80+
//UpdateNodes(Projects, newProjects);
7781

78-
Projects = new ObservableCollection<CodeExplorerItemViewModel>(newProjects);
82+
//Projects = new ObservableCollection<CodeExplorerItemViewModel>(newProjects);
7983

8084
IsBusy = false;
8185
}
@@ -101,16 +105,16 @@ private void UpdateNodes(IEnumerable<CodeExplorerItemViewModel> oldList, IEnumer
101105
i.QualifiedSelection.Value.Selection == item.QualifiedSelection.Value.Selection);
102106
}
103107

104-
if (oldItem != null)
105-
{
106-
item.IsExpanded = oldItem.IsExpanded;
107-
item.IsSelected = oldItem.IsSelected;
108+
//if (oldItem != null)
109+
//{
110+
// item.IsExpanded = oldItem.IsExpanded;
111+
// item.IsSelected = oldItem.IsSelected;
108112

109-
if (oldItem.Items.Any() && item.Items.Any())
110-
{
111-
UpdateNodes(oldItem.Items, item.Items);
112-
}
113-
}
113+
// if (oldItem.Items.Any() && item.Items.Any())
114+
// {
115+
// UpdateNodes(oldItem.Items, item.Items);
116+
// }
117+
//}
114118
}
115119
}
116120

Lines changed: 66 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
using System;
21
using System.Collections.Generic;
2+
using System.IO;
33
using System.Linq;
4-
using System.Runtime.InteropServices;
5-
using System.Windows.Media.Imaging;
64
using Rubberduck.Parsing.Symbols;
7-
using Rubberduck.VBEditor;
85
using Rubberduck.Parsing.Annotations;
9-
using Rubberduck.VBEditor.ComManagement;
106
using Rubberduck.VBEditor.SafeComWrappers;
117
using Rubberduck.Resources.CodeExplorer;
128
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
139

1410
namespace Rubberduck.Navigation.CodeExplorer
1511
{
16-
public class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
12+
public sealed class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
1713
{
18-
public override CodeExplorerItemViewModel Parent { get; }
19-
2014
public static readonly DeclarationType[] MemberTypes =
2115
{
2216
DeclarationType.Constant,
@@ -33,219 +27,98 @@ public class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
3327
DeclarationType.Variable
3428
};
3529

36-
public CodeExplorerComponentViewModel(CodeExplorerItemViewModel parent, Declaration declaration, IEnumerable<Declaration> declarations, IProjectsProvider projectsProvider, IVBE vbe)
37-
: base(declaration)
30+
private readonly IVBE _vbe;
31+
32+
public CodeExplorerComponentViewModel(ICodeExplorerNode parent, Declaration declaration, IEnumerable<Declaration> declarations, IVBE vbe)
33+
: base(parent, declaration)
3834
{
39-
Parent = parent;
40-
SetIcon();
41-
42-
Items = declarations.GroupBy(item => item.Scope).SelectMany(grouping =>
43-
grouping.Where(item => item.ParentDeclaration != null
44-
&& item.ParentScope == declaration.Scope
45-
&& MemberTypes.Contains(item.DeclarationType))
46-
.OrderBy(item => item.QualifiedSelection.Selection.StartLine)
47-
.Select(item => new CodeExplorerMemberViewModel(this, item, grouping)))
48-
.ToList<CodeExplorerItemViewModel>();
49-
50-
_name = DeclarationType == DeclarationType.ResFile && string.IsNullOrEmpty(Declaration.IdentifierName)
51-
? CodeExplorerUI.CodeExplorer_ResourceFileText
52-
: Declaration.IdentifierName;
53-
54-
var qualifiedModuleName = declaration.QualifiedName.QualifiedModuleName;
55-
try
56-
{
57-
switch (qualifiedModuleName.ComponentType)
58-
{
59-
case ComponentType.Document:
60-
var parenthesizedName = string.Empty;
61-
var state = DocumentState.Inaccessible;
62-
using (var app = vbe.HostApplication())
63-
{
64-
if (app != null)
65-
{
66-
var document = app.GetDocument(qualifiedModuleName);
67-
parenthesizedName = document?.DocumentName ?? string.Empty;
68-
state = document?.State ?? DocumentState.Inaccessible;
69-
}
70-
}
71-
72-
if (state == DocumentState.DesignView && ContainsBuiltinDocumentPropertiesProperty(projectsProvider))
73-
{
74-
CodeExplorerItemViewModel node = this;
75-
while (node.Parent != null)
76-
{
77-
node = node.Parent;
78-
}
79-
80-
if (node is CodeExplorerProjectViewModel projectNode)
81-
{
82-
projectNode.SetParenthesizedName(parenthesizedName);
83-
}
84-
}
85-
else
86-
{
87-
if (!string.IsNullOrWhiteSpace(parenthesizedName))
88-
{
89-
_name += " (" + parenthesizedName + ")";
90-
}
91-
}
92-
break;
35+
_vbe = vbe;
36+
SetName();
37+
AddNewChildren(declarations.ToList());
38+
}
9339

94-
case ComponentType.ResFile:
95-
var fileName = Declaration.IdentifierName.Split('\\').Last();
96-
_name = $"{CodeExplorerUI.CodeExplorer_ResourceFileText} ({fileName})";
97-
break;
40+
private string _name;
41+
public override string Name => _name;
9842

99-
case ComponentType.RelatedDocument:
100-
_name = $"({Declaration.IdentifierName.Split('\\').Last()})";
101-
break;
43+
public override string NameWithSignature => $"{Name}{(IsPredeclared ? " (Predeclared)" : string.Empty)}";
10244

103-
default:
104-
_name = Declaration.IdentifierName;
105-
break;
106-
}
107-
}
108-
catch
109-
{
110-
// gotcha! (this means that the property either doesn't exist or we weren't able to get it for some reason)
111-
}
112-
}
45+
public override Comparer<ICodeExplorerNode> SortComparer => CodeExplorerItemComparer.ComponentType;
11346

114-
private bool ContainsBuiltinDocumentPropertiesProperty(IProjectsProvider projectsProvider)
115-
{
116-
var component = projectsProvider.Component(Declaration.QualifiedName.QualifiedModuleName);
117-
using (var properties = component.Properties)
118-
{
119-
foreach (var property in properties)
120-
using(property)
121-
{
122-
if (property.Name == "BuiltinDocumentProperties")
123-
{
124-
return true;
125-
}
126-
}
47+
public bool IsPredeclared => Declaration != null &&
48+
Declaration.IsUserDefined &&
49+
Declaration.DeclarationType == DeclarationType.ClassModule &&
50+
Declaration.QualifiedName.QualifiedModuleName.ComponentType != ComponentType.Document &&
51+
Declaration.Attributes.HasPredeclaredIdAttribute(out _);
12752

128-
return false;
129-
}
130-
}
53+
public bool IsTestModule => Declaration.DeclarationType == DeclarationType.ProceduralModule
54+
&& Declaration.Annotations.Any(annotation => annotation.AnnotationType == AnnotationType.TestModule);
13155

132-
private bool _isErrorState;
133-
public bool IsErrorState
56+
public override void Synchronize(List<Declaration> updated)
13457
{
135-
get => _isErrorState;
136-
set
58+
base.Synchronize(updated);
59+
if (Declaration is null)
13760
{
138-
_isErrorState = value;
139-
_icon = GetImageSource(CodeExplorerUI.cross_circle);
140-
141-
142-
foreach (var item in Items)
143-
{
144-
((CodeExplorerMemberViewModel) item).ParentComponentHasError();
145-
}
146-
147-
OnPropertyChanged();
148-
// ReSharper disable ExplicitCallerInfoArgument
149-
OnPropertyChanged("CollapsedIcon");
150-
OnPropertyChanged("ExpandedIcon");
151-
// ReSharper restore ExplicitCallerInfoArgument
61+
return;
15262
}
63+
64+
// Document modules might have had the underlying COM object renamed since the last reparse. Let's check...
65+
SetName();
15366
}
15467

155-
public bool IsTestModule
68+
protected override void AddNewChildren(List<Declaration> updated)
15669
{
157-
get
70+
if (updated is null)
15871
{
159-
return Declaration.DeclarationType == DeclarationType.ProceduralModule
160-
&& Declaration.Annotations.Any(annotation => annotation.AnnotationType == AnnotationType.TestModule);
72+
return;
16173
}
162-
}
163-
164-
private readonly string _name;
165-
public override string Name => _name;
166-
167-
public override string NameWithSignature =>
168-
$"{_name}{(IsPredeclared ? " (Predeclared)" : string.Empty)}";
16974

170-
private bool IsPredeclared => Declaration != null &&
171-
DeclarationType == DeclarationType.ClassModule &&
172-
Declaration.Attributes.HasPredeclaredIdAttribute(out _);
173-
174-
public override QualifiedSelection? QualifiedSelection => Declaration.QualifiedSelection;
175-
176-
private ComponentType ComponentType => Declaration.QualifiedName.QualifiedModuleName.ComponentType;
75+
AddChildren(updated.GroupBy(item => item.Scope).SelectMany(grouping =>
76+
grouping.Where(item =>
77+
item.ParentDeclaration != null && item.ParentScope == Declaration.Scope &&
78+
MemberTypes.Contains(item.DeclarationType))
79+
.Select(item => new CodeExplorerMemberViewModel(this, item, grouping))));
80+
}
17781

178-
private static readonly IDictionary<ComponentType, DeclarationType> DeclarationTypes = new Dictionary<ComponentType, DeclarationType>
82+
private void SetName()
17983
{
180-
{ ComponentType.ClassModule, DeclarationType.ClassModule },
181-
{ ComponentType.StandardModule, DeclarationType.ProceduralModule },
182-
{ ComponentType.Document, DeclarationType.Document },
183-
{ ComponentType.UserForm, DeclarationType.UserForm },
184-
{ ComponentType.VBForm, DeclarationType.VbForm },
185-
{ ComponentType.MDIForm, DeclarationType.MdiForm},
186-
{ ComponentType.UserControl, DeclarationType.UserControl},
187-
{ ComponentType.DocObject, DeclarationType.DocObject},
188-
{ ComponentType.ResFile, DeclarationType.ResFile},
189-
{ ComponentType.RelatedDocument, DeclarationType.RelatedDocument},
190-
{ ComponentType.PropPage, DeclarationType.PropPage},
191-
{ ComponentType.ActiveXDesigner, DeclarationType.ActiveXDesigner}
192-
};
84+
_name = Declaration?.IdentifierName ?? string.Empty;
19385

194-
private DeclarationType DeclarationType
195-
{
196-
get
86+
if (Declaration is null)
19787
{
198-
var result = DeclarationType.ClassModule;
199-
try
200-
{
201-
DeclarationTypes.TryGetValue(ComponentType, out result);
202-
}
203-
catch (COMException exception)
204-
{
205-
Console.WriteLine(exception);
206-
}
207-
return result;
88+
return;
20889
}
209-
}
21090

211-
private static readonly BitmapImage PredeclaredIcon = GetImageSource(CodeExplorerUI.ObjectClassPredeclared);
212-
private static readonly BitmapImage OopsIcon = GetImageSource(CodeExplorerUI.status_offline);
91+
var qualifiedModuleName = Declaration.QualifiedName.QualifiedModuleName;
21392

214-
private static readonly IDictionary<DeclarationType,BitmapImage> Icons = new Dictionary<DeclarationType, BitmapImage>
215-
{
216-
{ DeclarationType.ClassModule, GetImageSource(CodeExplorerUI.ObjectClass) },
217-
{ DeclarationType.ProceduralModule, GetImageSource(CodeExplorerUI.ObjectModule) },
218-
{ DeclarationType.UserForm, GetImageSource(CodeExplorerUI.ProjectForm) },
219-
{ DeclarationType.Document, GetImageSource(CodeExplorerUI.document_office) },
220-
{ DeclarationType.VbForm, GetImageSource(CodeExplorerUI.ProjectForm)},
221-
{ DeclarationType.MdiForm, GetImageSource(CodeExplorerUI.MdiForm)},
222-
{ DeclarationType.UserControl, GetImageSource(CodeExplorerUI.ui_scroll_pane_form)},
223-
{ DeclarationType.DocObject, GetImageSource(CodeExplorerUI.document_globe)},
224-
{ DeclarationType.PropPage, GetImageSource(CodeExplorerUI.ui_tab_content)},
225-
{ DeclarationType.ActiveXDesigner, GetImageSource(CodeExplorerUI.pencil_ruler)},
226-
{ DeclarationType.ResFile, GetImageSource(CodeExplorerUI.document_block)},
227-
{ DeclarationType.RelatedDocument, GetImageSource(CodeExplorerUI.document_import)}
228-
};
229-
230-
private void SetIcon()
231-
{
232-
if (IsPredeclared)
93+
try
23394
{
234-
_icon = PredeclaredIcon;
235-
return;
236-
}
95+
switch (qualifiedModuleName.ComponentType)
96+
{
97+
case ComponentType.Document:
23798

238-
if (Icons.ContainsKey(DeclarationType))
99+
using (var app = _vbe.HostApplication())
100+
{
101+
var parenthesized = app?.GetDocument(qualifiedModuleName)?.DocumentName ?? string.Empty;
102+
_name = string.IsNullOrEmpty(parenthesized) ? _name : $"{_name} ({parenthesized})";
103+
}
104+
105+
break;
106+
case ComponentType.ResFile:
107+
_name = string.IsNullOrEmpty(_name)
108+
? CodeExplorerUI.CodeExplorer_ResourceFileText
109+
: $"{CodeExplorerUI.CodeExplorer_ResourceFileText} ({Path.GetFileName(_name)})";
110+
break;
111+
case ComponentType.RelatedDocument:
112+
_name = string.IsNullOrEmpty(_name) ? string.Empty : Path.GetFileName(_name);
113+
break;
114+
}
115+
}
116+
catch
239117
{
240-
_icon = Icons[DeclarationType];
241-
return;
118+
//Ignored;
242119
}
243120

244-
_icon = OopsIcon;
121+
OnNameChanged();
245122
}
246-
247-
private BitmapImage _icon;
248-
public override BitmapImage CollapsedIcon => _icon;
249-
public override BitmapImage ExpandedIcon => _icon;
250123
}
251124
}

0 commit comments

Comments
 (0)