Use observable collections for solution model
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using ObservableCollections;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
namespace SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
@@ -9,8 +10,8 @@ public class SharpIdeFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildShar
|
|||||||
public required IExpandableSharpIdeNode Parent { get; set; }
|
public required IExpandableSharpIdeNode Parent { get; set; }
|
||||||
public required string Path { get; set; }
|
public required string Path { get; set; }
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required List<SharpIdeFile> Files { get; set; }
|
public ObservableHashSet<SharpIdeFile> Files { get; init; }
|
||||||
public required List<SharpIdeFolder> Folders { get; set; }
|
public ObservableHashSet<SharpIdeFolder> Folders { get; init; }
|
||||||
public bool Expanded { get; set; }
|
public bool Expanded { get; set; }
|
||||||
|
|
||||||
[SetsRequiredMembers]
|
[SetsRequiredMembers]
|
||||||
@@ -19,8 +20,8 @@ public class SharpIdeFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildShar
|
|||||||
Parent = parent;
|
Parent = parent;
|
||||||
Path = folderInfo.FullName;
|
Path = folderInfo.FullName;
|
||||||
Name = folderInfo.Name;
|
Name = folderInfo.Name;
|
||||||
Files = folderInfo.GetFiles(this, allFiles);
|
Files = new ObservableHashSet<SharpIdeFile>(folderInfo.GetFiles(this, allFiles));
|
||||||
Folders = this.GetSubFolders(this, allFiles, allFolders);
|
Folders = new ObservableHashSet<SharpIdeFolder>(this.GetSubFolders(this, allFiles, allFolders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharpIdeFolder()
|
public SharpIdeFolder()
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
|||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required string FilePath { get; set; }
|
public required string FilePath { get; set; }
|
||||||
public required string DirectoryPath { get; set; }
|
public required string DirectoryPath { get; set; }
|
||||||
public required List<SharpIdeProjectModel> Projects { get; set; }
|
public required ObservableHashSet<SharpIdeProjectModel> Projects { get; set; }
|
||||||
public required List<SharpIdeSolutionFolder> SlnFolders { get; set; }
|
public required ObservableHashSet<SharpIdeSolutionFolder> SlnFolders { get; set; }
|
||||||
public required HashSet<SharpIdeProjectModel> AllProjects { get; set; }
|
public required HashSet<SharpIdeProjectModel> AllProjects { get; set; }
|
||||||
public required HashSet<SharpIdeFile> AllFiles { get; set; }
|
public required HashSet<SharpIdeFile> AllFiles { get; set; }
|
||||||
public required HashSet<SharpIdeFolder> AllFolders { get; set; }
|
public required HashSet<SharpIdeFolder> AllFolders { get; set; }
|
||||||
@@ -52,8 +52,8 @@ public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
|||||||
Name = solutionName;
|
Name = solutionName;
|
||||||
FilePath = solutionFilePath;
|
FilePath = solutionFilePath;
|
||||||
DirectoryPath = Path.GetDirectoryName(solutionFilePath)!;
|
DirectoryPath = Path.GetDirectoryName(solutionFilePath)!;
|
||||||
Projects = intermediateModel.Projects.Select(s => new SharpIdeProjectModel(s, allProjects, allFiles, allFolders, this)).ToList();
|
Projects = new ObservableHashSet<SharpIdeProjectModel>(intermediateModel.Projects.Select(s => new SharpIdeProjectModel(s, allProjects, allFiles, allFolders, this)));
|
||||||
SlnFolders = intermediateModel.SolutionFolders.Select(s => new SharpIdeSolutionFolder(s, allProjects, allFiles, allFolders, this)).ToList();
|
SlnFolders = new ObservableHashSet<SharpIdeSolutionFolder>(intermediateModel.SolutionFolders.Select(s => new SharpIdeSolutionFolder(s, allProjects, allFiles, allFolders, this)));
|
||||||
AllProjects = allProjects.ToHashSet();
|
AllProjects = allProjects.ToHashSet();
|
||||||
AllFiles = allFiles.ToHashSet();
|
AllFiles = allFiles.ToHashSet();
|
||||||
AllFolders = allFolders.ToHashSet();
|
AllFolders = allFolders.ToHashSet();
|
||||||
@@ -62,9 +62,9 @@ public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
|||||||
public class SharpIdeSolutionFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode
|
public class SharpIdeSolutionFolder : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required List<SharpIdeSolutionFolder> Folders { get; set; }
|
public required ObservableHashSet<SharpIdeSolutionFolder> Folders { get; set; }
|
||||||
public required List<SharpIdeProjectModel> Projects { get; set; }
|
public required ObservableHashSet<SharpIdeProjectModel> Projects { get; set; }
|
||||||
public required List<SharpIdeFile> Files { get; set; }
|
public required ObservableHashSet<SharpIdeFile> Files { get; set; }
|
||||||
public bool Expanded { get; set; }
|
public bool Expanded { get; set; }
|
||||||
public required IExpandableSharpIdeNode Parent { get; set; }
|
public required IExpandableSharpIdeNode Parent { get; set; }
|
||||||
|
|
||||||
@@ -73,17 +73,17 @@ public class SharpIdeSolutionFolder : ISharpIdeNode, IExpandableSharpIdeNode, IC
|
|||||||
{
|
{
|
||||||
Name = intermediateModel.Model.Name;
|
Name = intermediateModel.Model.Name;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
Files = intermediateModel.Files.Select(s => new SharpIdeFile(s.FullPath, s.Name, this, allFiles)).ToList();
|
Files = new ObservableHashSet<SharpIdeFile>(intermediateModel.Files.Select(s => new SharpIdeFile(s.FullPath, s.Name, this, allFiles)));
|
||||||
Folders = intermediateModel.Folders.Select(x => new SharpIdeSolutionFolder(x, allProjects, allFiles, allFolders, this)).ToList();
|
Folders = new ObservableHashSet<SharpIdeSolutionFolder>(intermediateModel.Folders.Select(x => new SharpIdeSolutionFolder(x, allProjects, allFiles, allFolders, this)));
|
||||||
Projects = intermediateModel.Projects.Select(x => new SharpIdeProjectModel(x, allProjects, allFiles, allFolders, this)).ToList();
|
Projects = new ObservableHashSet<SharpIdeProjectModel>(intermediateModel.Projects.Select(x => new SharpIdeProjectModel(x, allProjects, allFiles, allFolders, this)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class SharpIdeProjectModel : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode
|
public class SharpIdeProjectModel : ISharpIdeNode, IExpandableSharpIdeNode, IChildSharpIdeNode
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required string FilePath { get; set; }
|
public required string FilePath { get; set; }
|
||||||
public required List<SharpIdeFolder> Folders { get; set; }
|
public required ObservableHashSet<SharpIdeFolder> Folders { get; set; }
|
||||||
public required List<SharpIdeFile> Files { get; set; }
|
public required ObservableHashSet<SharpIdeFile> Files { get; set; }
|
||||||
public bool Expanded { get; set; }
|
public bool Expanded { get; set; }
|
||||||
public required IExpandableSharpIdeNode Parent { get; set; }
|
public required IExpandableSharpIdeNode Parent { get; set; }
|
||||||
public bool Running { get; set; }
|
public bool Running { get; set; }
|
||||||
@@ -96,8 +96,8 @@ public class SharpIdeProjectModel : ISharpIdeNode, IExpandableSharpIdeNode, IChi
|
|||||||
Parent = parent;
|
Parent = parent;
|
||||||
Name = projectModel.Model.ActualDisplayName;
|
Name = projectModel.Model.ActualDisplayName;
|
||||||
FilePath = projectModel.FullFilePath;
|
FilePath = projectModel.FullFilePath;
|
||||||
Files = TreeMapperV2.GetFiles(projectModel.FullFilePath, this, allFiles);
|
Files = new ObservableHashSet<SharpIdeFile>(TreeMapperV2.GetFiles(projectModel.FullFilePath, this, allFiles));
|
||||||
Folders = TreeMapperV2.GetSubFolders(projectModel.FullFilePath, this, allFiles, allFolders);
|
Folders = new ObservableHashSet<SharpIdeFolder>(TreeMapperV2.GetSubFolders(projectModel.FullFilePath, this, allFiles, allFolders));
|
||||||
MsBuildEvaluationProjectTask = ProjectEvaluation.GetProject(projectModel.FullFilePath);
|
MsBuildEvaluationProjectTask = ProjectEvaluation.GetProject(projectModel.FullFilePath);
|
||||||
allProjects.Add(this);
|
allProjects.Add(this);
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/SharpIDE.Godot/Features/Common/TreeItemContainer.cs
Normal file
24
src/SharpIDE.Godot/Features/Common/TreeItemContainer.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
|
using Godot;
|
||||||
|
using ObservableCollections;
|
||||||
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
|
namespace SharpIDE.Godot.Features.Common;
|
||||||
|
|
||||||
|
public class TreeItemContainer
|
||||||
|
{
|
||||||
|
public TreeItem? Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ObservableTreeExtensions
|
||||||
|
{
|
||||||
|
public static ObservableHashSet<T> WithInitialPopulation<T>(this ObservableHashSet<T> hashSet, Action<ViewChangedEvent<T, TreeItemContainer>> func) where T : class
|
||||||
|
{
|
||||||
|
foreach (var existing in hashSet)
|
||||||
|
{
|
||||||
|
var viewChangedEvent = new ViewChangedEvent<T, TreeItemContainer>(NotifyCollectionChangedAction.Add, (existing, new TreeItemContainer()), (null!, null!), 0, 0, new SortOperation<T>());
|
||||||
|
func(viewChangedEvent);
|
||||||
|
}
|
||||||
|
return hashSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using ObservableCollections;
|
|||||||
using R3;
|
using R3;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
using SharpIDE.Godot.Features.Common;
|
||||||
|
|
||||||
namespace SharpIDE.Godot.Features.Problems;
|
namespace SharpIDE.Godot.Features.Problems;
|
||||||
|
|
||||||
@@ -41,10 +42,7 @@ public partial class ProblemsPanel : Control
|
|||||||
BindToTree(_projects);
|
BindToTree(_projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TreeItemContainer
|
|
||||||
{
|
|
||||||
public TreeItem? Value { get; set; }
|
|
||||||
}
|
|
||||||
public void BindToTree(ObservableHashSet<SharpIdeProjectModel> list)
|
public void BindToTree(ObservableHashSet<SharpIdeProjectModel> list)
|
||||||
{
|
{
|
||||||
var view = list.CreateView(y => new TreeItemContainer());
|
var view = list.CreateView(y => new TreeItemContainer());
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
using Ardalis.GuardClauses;
|
using Ardalis.GuardClauses;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using ObservableCollections;
|
||||||
|
using R3;
|
||||||
using SharpIDE.Application.Features.Analysis;
|
using SharpIDE.Application.Features.Analysis;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
using SharpIDE.Godot.Features.Common;
|
||||||
using SharpIDE.Godot.Features.Problems;
|
using SharpIDE.Godot.Features.Problems;
|
||||||
|
|
||||||
namespace SharpIDE.Godot.Features.SolutionExplorer;
|
namespace SharpIDE.Godot.Features.SolutionExplorer;
|
||||||
@@ -22,6 +26,7 @@ public partial class SolutionExplorerPanel : MarginContainer
|
|||||||
|
|
||||||
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
|
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
|
||||||
private Tree _tree = null!;
|
private Tree _tree = null!;
|
||||||
|
private TreeItem _rootItem = null!;
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_tree = GetNode<Tree>("Tree");
|
_tree = GetNode<Tree>("Tree");
|
||||||
@@ -86,97 +91,170 @@ public partial class SolutionExplorerPanel : MarginContainer
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RepopulateTree()
|
public void BindToSolution() => BindToSolution(SolutionModel);
|
||||||
|
[RequiresGodotUiThread]
|
||||||
|
public void BindToSolution(SharpIdeSolutionModel solution)
|
||||||
{
|
{
|
||||||
_tree.Clear();
|
_tree.Clear();
|
||||||
|
|
||||||
var rootItem = _tree.CreateItem();
|
// Root
|
||||||
rootItem.SetText(0, SolutionModel.Name);
|
var rootItem = _tree.CreateItem();
|
||||||
rootItem.SetIcon(0, SlnIcon);
|
rootItem.SetText(0, solution.Name);
|
||||||
|
rootItem.SetIcon(0, SlnIcon);
|
||||||
|
_rootItem = rootItem;
|
||||||
|
|
||||||
// Add projects directly under solution
|
// Observe Projects
|
||||||
foreach (var project in SolutionModel.Projects)
|
var projectsView = solution.Projects
|
||||||
{
|
.WithInitialPopulation(s => CreateProjectTreeItem(_tree, _rootItem, s))
|
||||||
AddProjectToTree(rootItem, project);
|
.CreateView(y => new TreeItemContainer());
|
||||||
}
|
projectsView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (e, ct) => await (e.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateProjectTreeItem(_tree, _rootItem, e)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(e.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
// Add folders under solution
|
// Observe Solution Folders
|
||||||
foreach (var folder in SolutionModel.SlnFolders)
|
var foldersView = solution.SlnFolders
|
||||||
{
|
.WithInitialPopulation(s => CreateSlnFolderTreeItem(_tree, _rootItem, s))
|
||||||
AddSlnFolderToTree(rootItem, folder);
|
.CreateView(y => new TreeItemContainer());
|
||||||
}
|
foldersView.ObserveChanged()
|
||||||
rootItem.SetCollapsedRecursive(true);
|
.SubscribeAwait(async (e, ct) => await (e.Action switch
|
||||||
rootItem.Collapsed = false;
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateSlnFolderTreeItem(_tree, _rootItem, e)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(e.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
|
rootItem.SetCollapsedRecursive(true);
|
||||||
|
rootItem.Collapsed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddSlnFolderToTree(TreeItem parent, SharpIdeSolutionFolder folder)
|
[RequiresGodotUiThread]
|
||||||
|
private void CreateSlnFolderTreeItem(Tree tree, TreeItem parent, ViewChangedEvent<SharpIdeSolutionFolder, TreeItemContainer> e)
|
||||||
{
|
{
|
||||||
var folderItem = _tree.CreateItem(parent);
|
var folderItem = tree.CreateItem(parent);
|
||||||
folderItem.SetText(0, folder.Name);
|
folderItem.SetText(0, e.NewItem.Value.Name);
|
||||||
folderItem.SetIcon(0, SlnFolderIcon);
|
folderItem.SetIcon(0, SlnFolderIcon);
|
||||||
var container = new RefCountedContainer<SharpIdeSolutionFolder>(folder);
|
folderItem.SetMetadata(0, new RefCountedContainer<SharpIdeSolutionFolder>(e.NewItem.Value));
|
||||||
folderItem.SetMetadata(0, container);
|
e.NewItem.View.Value = folderItem;
|
||||||
|
|
||||||
foreach (var project in folder.Projects)
|
// Observe folder sub-collections
|
||||||
{
|
var subFoldersView = e.NewItem.Value.Folders
|
||||||
AddProjectToTree(folderItem, project);
|
.WithInitialPopulation(s => CreateSlnFolderTreeItem(_tree, folderItem, s))
|
||||||
}
|
.CreateView(y => new TreeItemContainer());
|
||||||
|
subFoldersView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateSlnFolderTreeItem(_tree, folderItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
foreach (var subFolder in folder.Folders)
|
var projectsView = e.NewItem.Value.Projects
|
||||||
{
|
.WithInitialPopulation(s => CreateProjectTreeItem(_tree, folderItem, s))
|
||||||
AddSlnFolderToTree(folderItem, subFolder); // recursion
|
.CreateView(y => new TreeItemContainer());
|
||||||
}
|
projectsView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateProjectTreeItem(_tree, folderItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
foreach (var sharpIdeFile in folder.Files)
|
var filesView = e.NewItem.Value.Files
|
||||||
{
|
.WithInitialPopulation(s => CreateFileTreeItem(_tree, folderItem, s))
|
||||||
AddFileToTree(folderItem, sharpIdeFile);
|
.CreateView(y => new TreeItemContainer());
|
||||||
}
|
filesView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateFileTreeItem(_tree, folderItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddProjectToTree(TreeItem parent, SharpIdeProjectModel project)
|
[RequiresGodotUiThread]
|
||||||
|
private void CreateProjectTreeItem(Tree tree, TreeItem parent, ViewChangedEvent<SharpIdeProjectModel, TreeItemContainer> e)
|
||||||
{
|
{
|
||||||
var projectItem = _tree.CreateItem(parent);
|
var projectItem = tree.CreateItem(parent);
|
||||||
projectItem.SetText(0, project.Name);
|
projectItem.SetText(0, e.NewItem.Value.Name);
|
||||||
projectItem.SetIcon(0, CsprojIcon);
|
projectItem.SetIcon(0, CsprojIcon);
|
||||||
var container = new RefCountedContainer<SharpIdeProjectModel>(project);
|
projectItem.SetMetadata(0, new RefCountedContainer<SharpIdeProjectModel>(e.NewItem.Value));
|
||||||
projectItem.SetMetadata(0, container);
|
e.NewItem.View.Value = projectItem;
|
||||||
|
|
||||||
foreach (var sharpIdeFolder in project.Folders)
|
// Observe project folders
|
||||||
{
|
var foldersView = e.NewItem.Value.Folders
|
||||||
AddFolderToTree(projectItem, sharpIdeFolder);
|
.WithInitialPopulation(s => CreateFolderTreeItem(_tree, projectItem, s))
|
||||||
}
|
.CreateView(y => new TreeItemContainer());
|
||||||
|
foldersView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateFolderTreeItem(_tree, projectItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
foreach (var file in project.Files)
|
// Observe project files
|
||||||
{
|
var filesView = e.NewItem.Value.Files
|
||||||
AddFileToTree(projectItem, file);
|
.WithInitialPopulation(s => CreateFileTreeItem(_tree, projectItem, s))
|
||||||
}
|
.CreateView(y => new TreeItemContainer());
|
||||||
|
filesView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateFileTreeItem(_tree, projectItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddFolderToTree(TreeItem projectItem, SharpIdeFolder sharpIdeFolder)
|
[RequiresGodotUiThread]
|
||||||
|
private void CreateFolderTreeItem(Tree tree, TreeItem parent, ViewChangedEvent<SharpIdeFolder, TreeItemContainer> e)
|
||||||
{
|
{
|
||||||
var folderItem = _tree.CreateItem(projectItem);
|
var folderItem = tree.CreateItem(parent);
|
||||||
folderItem.SetText(0, sharpIdeFolder.Name);
|
folderItem.SetText(0, e.NewItem.Value.Name);
|
||||||
folderItem.SetIcon(0, FolderIcon);
|
folderItem.SetIcon(0, FolderIcon);
|
||||||
var container = new RefCountedContainer<SharpIdeFolder>(sharpIdeFolder);
|
folderItem.SetMetadata(0, new RefCountedContainer<SharpIdeFolder>(e.NewItem.Value));
|
||||||
folderItem.SetMetadata(0, container);
|
e.NewItem.View.Value = folderItem;
|
||||||
|
|
||||||
foreach (var subFolder in sharpIdeFolder.Folders)
|
// Observe subfolders
|
||||||
{
|
var subFoldersView = e.NewItem.Value.Folders
|
||||||
AddFolderToTree(folderItem, subFolder); // recursion
|
.WithInitialPopulation(s => CreateFolderTreeItem(_tree, folderItem, s))
|
||||||
}
|
.CreateView(y => new TreeItemContainer());
|
||||||
|
subFoldersView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateFolderTreeItem(_tree, folderItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
|
|
||||||
foreach (var file in sharpIdeFolder.Files)
|
// Observe files
|
||||||
{
|
var filesView = e.NewItem.Value.Files
|
||||||
AddFileToTree(folderItem, file);
|
.WithInitialPopulation(s => CreateFileTreeItem(_tree, folderItem, s))
|
||||||
}
|
.CreateView(y => new TreeItemContainer());
|
||||||
|
filesView.ObserveChanged()
|
||||||
|
.SubscribeAwait(async (innerEvent, ct) => await (innerEvent.Action switch
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedAction.Add => this.InvokeAsync(() => CreateFileTreeItem(_tree, folderItem, innerEvent)),
|
||||||
|
NotifyCollectionChangedAction.Remove => FreeTreeItem(innerEvent.OldItem.View.Value),
|
||||||
|
_ => Task.CompletedTask
|
||||||
|
})).AddTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddFileToTree(TreeItem parent, SharpIdeFile file)
|
[RequiresGodotUiThread]
|
||||||
|
private void CreateFileTreeItem(Tree tree, TreeItem parent, ViewChangedEvent<SharpIdeFile, TreeItemContainer> e)
|
||||||
{
|
{
|
||||||
var fileItem = _tree.CreateItem(parent);
|
var fileItem = tree.CreateItem(parent);
|
||||||
fileItem.SetText(0, file.Name);
|
fileItem.SetText(0, e.NewItem.Value.Name);
|
||||||
fileItem.SetIcon(0, CsharpFileIcon);
|
fileItem.SetIcon(0, CsharpFileIcon);
|
||||||
var container = new RefCountedContainer<SharpIdeFile>(file);
|
fileItem.SetMetadata(0, new RefCountedContainer<SharpIdeFile>(e.NewItem.Value));
|
||||||
fileItem.SetMetadata(0, container);
|
e.NewItem.View.Value = fileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FreeTreeItem(TreeItem? item)
|
||||||
|
{
|
||||||
|
await this.InvokeAsync(() => item?.Free());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ public partial class IdeRoot : Control
|
|||||||
_searchAllFilesWindow.Solution = solutionModel;
|
_searchAllFilesWindow.Solution = solutionModel;
|
||||||
_fileExternalChangeHandler.SolutionModel = solutionModel;
|
_fileExternalChangeHandler.SolutionModel = solutionModel;
|
||||||
_fileChangedService.SolutionModel = solutionModel;
|
_fileChangedService.SolutionModel = solutionModel;
|
||||||
Callable.From(_solutionExplorerPanel.RepopulateTree).CallDeferred();
|
Callable.From(_solutionExplorerPanel.BindToSolution).CallDeferred();
|
||||||
_roslynAnalysis.StartSolutionAnalysis(solutionModel);
|
_roslynAnalysis.StartSolutionAnalysis(solutionModel);
|
||||||
_fileWatcher.StartWatching(solutionModel);
|
_fileWatcher.StartWatching(solutionModel);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user