Skip to content

Commit

Permalink
Remembered the expanded state of nodes in the Project Filter dialog.
Browse files Browse the repository at this point in the history
Fixes #5
  • Loading branch information
reduckted committed Dec 23, 2023
1 parent e9f6ba3 commit ff17117
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 47 deletions.
48 changes: 31 additions & 17 deletions source/ProjectFilter/Commands/FilterProjectsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ protected async override Task ExecuteAsync(OleMenuCmdEventArgs e) {
IHierarchyProvider hierarchyProvider;
TextFilterFactory textFilterFactory;
Func<Task<IEnumerable<IHierarchyNode>>> hierarchyFactory;
IExtensionSettings globalSettings;
ISolutionSettingsManager solutionSettingsManager;
SolutionSettings? solutionSettings;


await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
Expand All @@ -43,19 +46,16 @@ protected async override Task ExecuteAsync(OleMenuCmdEventArgs e) {
textFilterFactory = await CreateTextFilterFactoryAsync();
hierarchyFactory = async () => await hierarchyProvider.GetHierarchyAsync();

using (var vm = new FilterDialogViewModel(hierarchyFactory, Debouncer.Create, textFilterFactory, Package.JoinableTaskFactory)) {
IExtensionSettings globalSettings;
ISolutionSettingsManager solutionSettingsManager;
SolutionSettings? solutionSettings;
FilterDialog dialog;
bool result;
globalSettings = await VS.GetRequiredServiceAsync<IExtensionSettings, IExtensionSettings>();
await globalSettings.LoadAsync();

solutionSettingsManager = await VS.GetRequiredServiceAsync<ISolutionSettingsManager, ISolutionSettingsManager>();
solutionSettings = await solutionSettingsManager.GetSettingsAsync();

globalSettings = await VS.GetRequiredServiceAsync<IExtensionSettings, IExtensionSettings>();
await globalSettings.LoadAsync();
using (var vm = new FilterDialogViewModel(hierarchyFactory, Debouncer.Create, textFilterFactory, solutionSettings?.Nodes, Package.JoinableTaskFactory)) {
FilterDialog dialog;
bool result;

solutionSettingsManager = await VS.GetRequiredServiceAsync<ISolutionSettingsManager, ISolutionSettingsManager>();
solutionSettings = await solutionSettingsManager.GetSettingsAsync();

// Initialize the settings with the settings that were last
// used for this solution. If this solution hasn't been
Expand All @@ -73,13 +73,14 @@ protected async override Task ExecuteAsync(OleMenuCmdEventArgs e) {
// Save the settings for this solution, even if filtering
// was cancelled. This saves the user from having to re-apply
// the settings the next time they open the dialog.
solutionSettingsManager.SetSettings(
new SolutionSettings {
LoadProjectDependencies = vm.LoadProjectDependencies,
UseRegularExpressions = vm.UseRegularExpressions,
ExpandLoadedProjects = vm.ExpandLoadedProjects
}
);
solutionSettings = new SolutionSettings {
LoadProjectDependencies = vm.LoadProjectDependencies,
UseRegularExpressions = vm.UseRegularExpressions,
ExpandLoadedProjects = vm.ExpandLoadedProjects
};
PopulateNodeSettings(vm.Items, solutionSettings.Nodes);

solutionSettingsManager.SetSettings(solutionSettings);

// Also save the settings to the global settings so that the same settings
// can be used for solutions that don't have their own settings yet.
Expand All @@ -97,6 +98,19 @@ protected async override Task ExecuteAsync(OleMenuCmdEventArgs e) {
}


private static void PopulateNodeSettings(HierarchyTreeViewItemCollection items, Dictionary<string, SolutionNodeSettings> settings) {
foreach (var item in items) {
SolutionNodeSettings nodeSettings;


nodeSettings = new SolutionNodeSettings { IsExpanded = item.IsExpanded };
PopulateNodeSettings(item.Children, nodeSettings.Children);

settings[item.Name] = nodeSettings;
}
}


private static async Task<TextFilterFactory> CreateTextFilterFactoryAsync() {
IPatternMatcherFactory patternMatcherFactory;

Expand Down
19 changes: 19 additions & 0 deletions source/ProjectFilter/Services/SolutionNodeSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;


namespace ProjectFilter.Services;


public class SolutionNodeSettings {

public SolutionNodeSettings() {
Children = new Dictionary<string, SolutionNodeSettings>();
}


public bool IsExpanded { get; set; }


public Dictionary<string, SolutionNodeSettings> Children { get; }

}
7 changes: 7 additions & 0 deletions source/ProjectFilter/Services/SolutionSettings.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Collections.Generic;


namespace ProjectFilter.Services;


Expand All @@ -7,6 +10,7 @@ public SolutionSettings() {
LoadProjectDependencies = true;
UseRegularExpressions = false;
ExpandLoadedProjects = true;
Nodes = new Dictionary<string, SolutionNodeSettings>();
}


Expand All @@ -18,4 +22,7 @@ public SolutionSettings() {

public bool ExpandLoadedProjects { get; set; }


public Dictionary<string, SolutionNodeSettings> Nodes { get; }

}
25 changes: 22 additions & 3 deletions source/ProjectFilter/UI/FilterDialogViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public sealed class FilterDialogViewModel : ObservableObject, IDisposable {

private readonly Func<Task<IEnumerable<IHierarchyNode>>> _hierarchyFactory;
private readonly TextFilterFactory _textFilterFactory;
private readonly Dictionary<string, SolutionNodeSettings>? _nodeSettings;
private readonly IDebouncer _debouncer;
private HierarchyTreeViewItemCollection _items;
private string _searchText;
Expand All @@ -35,6 +36,7 @@ public FilterDialogViewModel(
Func<Task<IEnumerable<IHierarchyNode>>> hierarchyFactory,
Func<TimeSpan, IDebouncer> debouncerFactory,
TextFilterFactory textFilterFactory,
Dictionary<string, SolutionNodeSettings>? nodeSettings,
JoinableTaskFactory joinableTaskFactory
) {
if (debouncerFactory is null) {
Expand All @@ -43,6 +45,7 @@ JoinableTaskFactory joinableTaskFactory

_hierarchyFactory = hierarchyFactory ?? throw new ArgumentNullException(nameof(hierarchyFactory));
_textFilterFactory = textFilterFactory ?? throw new ArgumentNullException(nameof(textFilterFactory));
_nodeSettings = nodeSettings;

_items = new HierarchyTreeViewItemCollection(Enumerable.Empty<HierarchyTreeViewItem>());
_searchText = "";
Expand Down Expand Up @@ -119,18 +122,24 @@ public async Task OnLoadedAsync() {

hierarchy = await _hierarchyFactory.Invoke();

Items = new HierarchyTreeViewItemCollection(hierarchy.Select(CreateItem));
Items = new HierarchyTreeViewItemCollection(
hierarchy.Select((x) => CreateItem(x, GetSettingsForNode(x, _nodeSettings)))
);

LoadedVisibility = Visibility.Visible;
LoadingVisibility = Visibility.Collapsed;
}


private static HierarchyTreeViewItem CreateItem(IHierarchyNode node) {
private static HierarchyTreeViewItem CreateItem(IHierarchyNode node, SolutionNodeSettings? nodeSettings) {
HierarchyTreeViewItem item;


item = new HierarchyTreeViewItem(node, node.Children.Select(CreateItem));
item = new HierarchyTreeViewItem(
node,
nodeSettings?.IsExpanded ?? true,
node.Children.Select((x) => CreateItem(x, GetSettingsForNode(x, nodeSettings?.Children)))
);

// Set the checked state of the item. If it has children, then we check
// it based on whether all or none of the children are checked. If it
Expand All @@ -148,6 +157,16 @@ private static HierarchyTreeViewItem CreateItem(IHierarchyNode node) {
}


private static SolutionNodeSettings? GetSettingsForNode(IHierarchyNode node, Dictionary<string, SolutionNodeSettings>? nodeSettings) {
if (nodeSettings is not null) {
nodeSettings.TryGetValue(node.Name, out SolutionNodeSettings settings);
return settings;
}

return null;
}


public Visibility LoadingVisibility {
get { return _loadingVisibility; }
private set { SetProperty(ref _loadingVisibility, value); }
Expand Down
3 changes: 2 additions & 1 deletion source/ProjectFilter/UI/HierarchyTreeViewItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ public class HierarchyTreeViewItem : ObservableObject {

public HierarchyTreeViewItem(
IHierarchyNode node,
bool isExpanded,
IEnumerable<HierarchyTreeViewItem> children
) {
_node = node;
Children = new HierarchyTreeViewItemCollection(children);

_isChecked = false;
_isExpanded = true;
_isExpanded = isExpanded;

// Connect the children to this parent item.
foreach (var child in Children) {
Expand Down
2 changes: 1 addition & 1 deletion tests/ProjectFilter.UnitTests/Helpers/Factory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static HierarchyTreeViewItem CreateTreeViewItem(string name = "", IEnumer
node = Substitute.For<IHierarchyNode>();
node.Name.Returns(name);

return new HierarchyTreeViewItem(node, children ?? Enumerable.Empty<HierarchyTreeViewItem>()) {
return new HierarchyTreeViewItem(node, true, children ?? Enumerable.Empty<HierarchyTreeViewItem>()) {
IsChecked = isChecked
};
}
Expand Down
Loading

0 comments on commit ff17117

Please sign in to comment.