Skip to content

Commit

Permalink
Code Explorer performance rewrite.
Browse files Browse the repository at this point in the history
  • Loading branch information
comintern committed Jan 14, 2019
1 parent b6aa90c commit 0a22f25
Show file tree
Hide file tree
Showing 40 changed files with 1,909 additions and 1,668 deletions.
46 changes: 25 additions & 21 deletions Rubberduck.Core/CodeAnalysis/CodeMetrics/CodeMetricsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ public class CodeMetricsViewModel : ViewModelBase, IDisposable
{
private readonly RubberduckParserState _state;
private readonly ICodeMetricsAnalyst _analyst;
private readonly FolderHelper _folderHelper;
//private readonly FolderHelper _folderHelper;
private readonly IVBE _vbe;

public CodeMetricsViewModel(RubberduckParserState state, ICodeMetricsAnalyst analyst, FolderHelper folderHelper, IVBE vbe)
public CodeMetricsViewModel(
RubberduckParserState state,
ICodeMetricsAnalyst analyst,
//FolderHelper folderHelper,
IVBE vbe)
{
_state = state;
_analyst = analyst;
_folderHelper = folderHelper;
//_folderHelper = folderHelper;
_state.StateChanged += OnStateChanged;
_vbe = vbe;
}
Expand Down Expand Up @@ -65,17 +69,17 @@ private void UpdateData()
.GroupBy(declaration => declaration.ProjectId)
.ToList();

var newProjects = userDeclarations
.Where(grouping => grouping.Any(declaration => declaration.DeclarationType == DeclarationType.Project))
.Select(grouping =>
new CodeExplorerProjectViewModel(_folderHelper,
grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project),
grouping,
_vbe)).ToList();
//var newProjects = userDeclarations
// .Where(grouping => grouping.Any(declaration => declaration.DeclarationType == DeclarationType.Project))
// .Select(grouping =>
// new CodeExplorerProjectViewModel(_folderHelper,
// grouping.SingleOrDefault(declaration => declaration.DeclarationType == DeclarationType.Project),
// grouping,
// _vbe)).ToList();

UpdateNodes(Projects, newProjects);
//UpdateNodes(Projects, newProjects);

Projects = new ObservableCollection<CodeExplorerItemViewModel>(newProjects);
//Projects = new ObservableCollection<CodeExplorerItemViewModel>(newProjects);

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

if (oldItem != null)
{
item.IsExpanded = oldItem.IsExpanded;
item.IsSelected = oldItem.IsSelected;
//if (oldItem != null)
//{
// item.IsExpanded = oldItem.IsExpanded;
// item.IsSelected = oldItem.IsSelected;

if (oldItem.Items.Any() && item.Items.Any())
{
UpdateNodes(oldItem.Items, item.Items);
}
}
// if (oldItem.Items.Any() && item.Items.Any())
// {
// UpdateNodes(oldItem.Items, item.Items);
// }
//}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Media.Imaging;
using Rubberduck.Parsing.Symbols;
using Rubberduck.VBEditor;
using Rubberduck.Parsing.Annotations;
using Rubberduck.VBEditor.ComManagement;
using Rubberduck.VBEditor.SafeComWrappers;
using Rubberduck.Resources.CodeExplorer;
using Rubberduck.VBEditor.SafeComWrappers.Abstract;

namespace Rubberduck.Navigation.CodeExplorer
{
public class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
public sealed class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
{
public override CodeExplorerItemViewModel Parent { get; }

public static readonly DeclarationType[] MemberTypes =
{
DeclarationType.Constant,
Expand All @@ -33,219 +27,98 @@ public class CodeExplorerComponentViewModel : CodeExplorerItemViewModel
DeclarationType.Variable
};

public CodeExplorerComponentViewModel(CodeExplorerItemViewModel parent, Declaration declaration, IEnumerable<Declaration> declarations, IProjectsProvider projectsProvider, IVBE vbe)
: base(declaration)
private readonly IVBE _vbe;

public CodeExplorerComponentViewModel(ICodeExplorerNode parent, Declaration declaration, IEnumerable<Declaration> declarations, IVBE vbe)
: base(parent, declaration)
{
Parent = parent;
SetIcon();

Items = declarations.GroupBy(item => item.Scope).SelectMany(grouping =>
grouping.Where(item => item.ParentDeclaration != null
&& item.ParentScope == declaration.Scope
&& MemberTypes.Contains(item.DeclarationType))
.OrderBy(item => item.QualifiedSelection.Selection.StartLine)
.Select(item => new CodeExplorerMemberViewModel(this, item, grouping)))
.ToList<CodeExplorerItemViewModel>();

_name = DeclarationType == DeclarationType.ResFile && string.IsNullOrEmpty(Declaration.IdentifierName)
? CodeExplorerUI.CodeExplorer_ResourceFileText
: Declaration.IdentifierName;

var qualifiedModuleName = declaration.QualifiedName.QualifiedModuleName;
try
{
switch (qualifiedModuleName.ComponentType)
{
case ComponentType.Document:
var parenthesizedName = string.Empty;
var state = DocumentState.Inaccessible;
using (var app = vbe.HostApplication())
{
if (app != null)
{
var document = app.GetDocument(qualifiedModuleName);
parenthesizedName = document?.DocumentName ?? string.Empty;
state = document?.State ?? DocumentState.Inaccessible;
}
}

if (state == DocumentState.DesignView && ContainsBuiltinDocumentPropertiesProperty(projectsProvider))
{
CodeExplorerItemViewModel node = this;
while (node.Parent != null)
{
node = node.Parent;
}

if (node is CodeExplorerProjectViewModel projectNode)
{
projectNode.SetParenthesizedName(parenthesizedName);
}
}
else
{
if (!string.IsNullOrWhiteSpace(parenthesizedName))
{
_name += " (" + parenthesizedName + ")";
}
}
break;
_vbe = vbe;
SetName();
AddNewChildren(declarations.ToList());
}

case ComponentType.ResFile:
var fileName = Declaration.IdentifierName.Split('\\').Last();
_name = $"{CodeExplorerUI.CodeExplorer_ResourceFileText} ({fileName})";
break;
private string _name;
public override string Name => _name;

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

default:
_name = Declaration.IdentifierName;
break;
}
}
catch
{
// gotcha! (this means that the property either doesn't exist or we weren't able to get it for some reason)
}
}
public override Comparer<ICodeExplorerNode> SortComparer => CodeExplorerItemComparer.ComponentType;

private bool ContainsBuiltinDocumentPropertiesProperty(IProjectsProvider projectsProvider)
{
var component = projectsProvider.Component(Declaration.QualifiedName.QualifiedModuleName);
using (var properties = component.Properties)
{
foreach (var property in properties)
using(property)
{
if (property.Name == "BuiltinDocumentProperties")
{
return true;
}
}
public bool IsPredeclared => Declaration != null &&
Declaration.IsUserDefined &&
Declaration.DeclarationType == DeclarationType.ClassModule &&
Declaration.QualifiedName.QualifiedModuleName.ComponentType != ComponentType.Document &&
Declaration.Attributes.HasPredeclaredIdAttribute(out _);

return false;
}
}
public bool IsTestModule => Declaration.DeclarationType == DeclarationType.ProceduralModule
&& Declaration.Annotations.Any(annotation => annotation.AnnotationType == AnnotationType.TestModule);

private bool _isErrorState;
public bool IsErrorState
public override void Synchronize(List<Declaration> updated)
{
get => _isErrorState;
set
base.Synchronize(updated);
if (Declaration is null)
{
_isErrorState = value;
_icon = GetImageSource(CodeExplorerUI.cross_circle);


foreach (var item in Items)
{
((CodeExplorerMemberViewModel) item).ParentComponentHasError();
}

OnPropertyChanged();
// ReSharper disable ExplicitCallerInfoArgument
OnPropertyChanged("CollapsedIcon");
OnPropertyChanged("ExpandedIcon");
// ReSharper restore ExplicitCallerInfoArgument
return;
}

// Document modules might have had the underlying COM object renamed since the last reparse. Let's check...
SetName();
}

public bool IsTestModule
protected override void AddNewChildren(List<Declaration> updated)
{
get
if (updated is null)
{
return Declaration.DeclarationType == DeclarationType.ProceduralModule
&& Declaration.Annotations.Any(annotation => annotation.AnnotationType == AnnotationType.TestModule);
return;
}
}

private readonly string _name;
public override string Name => _name;

public override string NameWithSignature =>
$"{_name}{(IsPredeclared ? " (Predeclared)" : string.Empty)}";

private bool IsPredeclared => Declaration != null &&
DeclarationType == DeclarationType.ClassModule &&
Declaration.Attributes.HasPredeclaredIdAttribute(out _);

public override QualifiedSelection? QualifiedSelection => Declaration.QualifiedSelection;

private ComponentType ComponentType => Declaration.QualifiedName.QualifiedModuleName.ComponentType;
AddChildren(updated.GroupBy(item => item.Scope).SelectMany(grouping =>
grouping.Where(item =>
item.ParentDeclaration != null && item.ParentScope == Declaration.Scope &&
MemberTypes.Contains(item.DeclarationType))
.Select(item => new CodeExplorerMemberViewModel(this, item, grouping))));
}

private static readonly IDictionary<ComponentType, DeclarationType> DeclarationTypes = new Dictionary<ComponentType, DeclarationType>
private void SetName()
{
{ ComponentType.ClassModule, DeclarationType.ClassModule },
{ ComponentType.StandardModule, DeclarationType.ProceduralModule },
{ ComponentType.Document, DeclarationType.Document },
{ ComponentType.UserForm, DeclarationType.UserForm },
{ ComponentType.VBForm, DeclarationType.VbForm },
{ ComponentType.MDIForm, DeclarationType.MdiForm},
{ ComponentType.UserControl, DeclarationType.UserControl},
{ ComponentType.DocObject, DeclarationType.DocObject},
{ ComponentType.ResFile, DeclarationType.ResFile},
{ ComponentType.RelatedDocument, DeclarationType.RelatedDocument},
{ ComponentType.PropPage, DeclarationType.PropPage},
{ ComponentType.ActiveXDesigner, DeclarationType.ActiveXDesigner}
};
_name = Declaration?.IdentifierName ?? string.Empty;

private DeclarationType DeclarationType
{
get
if (Declaration is null)
{
var result = DeclarationType.ClassModule;
try
{
DeclarationTypes.TryGetValue(ComponentType, out result);
}
catch (COMException exception)
{
Console.WriteLine(exception);
}
return result;
return;
}
}

private static readonly BitmapImage PredeclaredIcon = GetImageSource(CodeExplorerUI.ObjectClassPredeclared);
private static readonly BitmapImage OopsIcon = GetImageSource(CodeExplorerUI.status_offline);
var qualifiedModuleName = Declaration.QualifiedName.QualifiedModuleName;

private static readonly IDictionary<DeclarationType,BitmapImage> Icons = new Dictionary<DeclarationType, BitmapImage>
{
{ DeclarationType.ClassModule, GetImageSource(CodeExplorerUI.ObjectClass) },
{ DeclarationType.ProceduralModule, GetImageSource(CodeExplorerUI.ObjectModule) },
{ DeclarationType.UserForm, GetImageSource(CodeExplorerUI.ProjectForm) },
{ DeclarationType.Document, GetImageSource(CodeExplorerUI.document_office) },
{ DeclarationType.VbForm, GetImageSource(CodeExplorerUI.ProjectForm)},
{ DeclarationType.MdiForm, GetImageSource(CodeExplorerUI.MdiForm)},
{ DeclarationType.UserControl, GetImageSource(CodeExplorerUI.ui_scroll_pane_form)},
{ DeclarationType.DocObject, GetImageSource(CodeExplorerUI.document_globe)},
{ DeclarationType.PropPage, GetImageSource(CodeExplorerUI.ui_tab_content)},
{ DeclarationType.ActiveXDesigner, GetImageSource(CodeExplorerUI.pencil_ruler)},
{ DeclarationType.ResFile, GetImageSource(CodeExplorerUI.document_block)},
{ DeclarationType.RelatedDocument, GetImageSource(CodeExplorerUI.document_import)}
};

private void SetIcon()
{
if (IsPredeclared)
try
{
_icon = PredeclaredIcon;
return;
}
switch (qualifiedModuleName.ComponentType)
{
case ComponentType.Document:

if (Icons.ContainsKey(DeclarationType))
using (var app = _vbe.HostApplication())
{
var parenthesized = app?.GetDocument(qualifiedModuleName)?.DocumentName ?? string.Empty;
_name = string.IsNullOrEmpty(parenthesized) ? _name : $"{_name} ({parenthesized})";
}

break;
case ComponentType.ResFile:
_name = string.IsNullOrEmpty(_name)
? CodeExplorerUI.CodeExplorer_ResourceFileText
: $"{CodeExplorerUI.CodeExplorer_ResourceFileText} ({Path.GetFileName(_name)})";
break;
case ComponentType.RelatedDocument:
_name = string.IsNullOrEmpty(_name) ? string.Empty : Path.GetFileName(_name);
break;
}
}
catch
{
_icon = Icons[DeclarationType];
return;
//Ignored;
}

_icon = OopsIcon;
OnNameChanged();
}

private BitmapImage _icon;
public override BitmapImage CollapsedIcon => _icon;
public override BitmapImage ExpandedIcon => _icon;
}
}

0 comments on commit 0a22f25

Please sign in to comment.