Skip to content

Commit 64ffb81

Browse files
Renamed SolutionExplorerNode to ItemNode
1 parent 075e021 commit 64ffb81

File tree

8 files changed

+359
-26
lines changed

8 files changed

+359
-26
lines changed

src/Community.VisualStudio.Toolkit.Shared/Events/SelectionEvents.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ int IVsSelectionEvents.OnSelectionChanged(IVsHierarchy pHierOld, uint itemidOld,
3737
{
3838
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
3939

40-
IVsHierarchyItem? from = await pHierOld.ToHierarcyItemAsync(itemidOld);
41-
IVsHierarchyItem? to = await pHierNew.ToHierarcyItemAsync(itemidNew);
40+
ItemNode? from = await ItemNode.CreateAsync(pHierOld, itemidOld);
41+
ItemNode? to = await ItemNode.CreateAsync(pHierNew, itemidNew);
4242

4343
SelectionChanged?.Invoke(this, new SelectionChangedEventArgs(from, to));
4444
}).FireAndForget();
@@ -66,7 +66,7 @@ public class SelectionChangedEventArgs : EventArgs
6666
/// <summary>
6767
/// Creates a new instance of the EventArgs.
6868
/// </summary>
69-
public SelectionChangedEventArgs(IVsHierarchyItem? from, IVsHierarchyItem? to)
69+
public SelectionChangedEventArgs(ItemNode? from, ItemNode? to)
7070
{
7171
From = from;
7272
To = to;
@@ -75,11 +75,11 @@ public SelectionChangedEventArgs(IVsHierarchyItem? from, IVsHierarchyItem? to)
7575
/// <summary>
7676
/// What the selection was before the change.
7777
/// </summary>
78-
public IVsHierarchyItem? From { get; }
78+
public ItemNode? From { get; }
7979

8080
/// <summary>
8181
/// What the selection is currently after the change.
8282
/// </summary>
83-
public IVsHierarchyItem? To { get; }
83+
public ItemNode? To { get; }
8484
}
8585
}

src/Community.VisualStudio.Toolkit.Shared/ExtensionMethods/IVsHierarchyExtensions.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,7 @@ public static class IVsHierarchyExtensions
2020
/// </remarks>
2121
public static bool TryGetItemProperty<T>(this IVsHierarchy hierarchy, uint itemId, int propertyId, out T? value)
2222
{
23-
ThreadHelper.ThrowIfNotOnUIThread();
24-
25-
if (ErrorHandler.Failed(hierarchy.GetProperty(itemId, propertyId, out var property)) || !(property is T))
26-
{
27-
value = default;
28-
return false;
29-
}
30-
31-
value = (T)property;
32-
33-
return true;
23+
return HierarchyUtilities.TryGetHierarchyProperty<T>(hierarchy, itemId, propertyId, out value);
3424
}
3525

3626
/// <summary>

src/Community.VisualStudio.Toolkit.Shared/Helpers/ProjectTypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace EnvDTE
1+
namespace Community.VisualStudio.Toolkit
22
{
33
/// <summary>
44
/// A list of known project types guids.
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
using System.Collections.Generic;
2+
using System.Diagnostics;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.Internal.VisualStudio.PlatformUI;
6+
using Microsoft.VisualStudio.Shell;
7+
using Microsoft.VisualStudio.Shell.Interop;
8+
9+
namespace Community.VisualStudio.Toolkit
10+
{
11+
/// <summary>
12+
/// A node reprensenting a file, folder, project or other item in Solution Explorer.
13+
/// </summary>
14+
[DebuggerDisplay("{Name} ({Type})")]
15+
public class ItemNode
16+
{
17+
private ItemNode? _parent;
18+
private IEnumerable<ItemNode?>? _children;
19+
private IVsHierarchy _hierarchy;
20+
private uint _itemId;
21+
22+
private ItemNode(IVsHierarchyItem item)
23+
{
24+
ThreadHelper.ThrowIfNotOnUIThread();
25+
26+
_hierarchy = item.HierarchyIdentity.IsNestedItem ? item.HierarchyIdentity.NestedHierarchy : item.HierarchyIdentity.Hierarchy;
27+
_itemId = item.HierarchyIdentity.IsNestedItem ? item.HierarchyIdentity.NestedItemID : item.HierarchyIdentity.ItemID;
28+
29+
_hierarchy.GetCanonicalName(_itemId, out var fileName);
30+
31+
FileName = fileName;
32+
Item = item;
33+
Name = item.Text;
34+
Type = GetNodeType(item.HierarchyIdentity);
35+
IsExpandable = HierarchyUtilities.IsExpandable(item.HierarchyIdentity);
36+
IsFaulted = HierarchyUtilities.IsFaultedProject(item.HierarchyIdentity);
37+
IsHidden = HierarchyUtilities.IsHiddenItem(_hierarchy, _itemId);
38+
IsRoot = item.HierarchyIdentity.IsRoot;
39+
IsNested = item.HierarchyIdentity.IsNestedItem;
40+
}
41+
42+
/// <summary>
43+
/// The underlying hierarchy item.
44+
/// </summary>
45+
public IVsHierarchyItem Item { get; }
46+
47+
/// <summary>
48+
/// The display name of the node
49+
/// </summary>
50+
public string Name { get; set; }
51+
52+
/// <summary>
53+
/// The absolute file path on disk.
54+
/// </summary>
55+
public string FileName { get; set; }
56+
57+
/// <summary>
58+
/// The type of node.
59+
/// </summary>
60+
public NodeType Type { get; }
61+
62+
/// <summary>
63+
/// A value indicating if the node can be expanded.
64+
/// </summary>
65+
public bool IsExpandable { get; }
66+
67+
/// <summary>
68+
/// A value indicating if the node is in a faulted state.
69+
/// </summary>
70+
public bool IsFaulted { get; }
71+
72+
/// <summary>
73+
/// A value indicating if the node is hidden.
74+
/// </summary>
75+
public bool IsHidden { get; }
76+
77+
/// <summary>
78+
/// A value indicating if the node is a root node.
79+
/// </summary>
80+
public bool IsRoot { get; }
81+
82+
/// <summary>
83+
/// A value indicating if the node is nested
84+
/// </summary>
85+
public bool IsNested { get; }
86+
87+
/// <summary>
88+
/// The parent node. Is <see langword="null"/> when there is no parent.
89+
/// </summary>
90+
public ItemNode? Parent => _parent ??= Create(Item.Parent);
91+
92+
/// <summary>
93+
/// A list of child nodes.
94+
/// </summary>
95+
public IEnumerable<ItemNode?> Children => _children ??= Item.Children.Select(t => Create(t));
96+
97+
/// <summary>
98+
/// Checks what kind the project is.
99+
/// </summary>
100+
/// <param name="typeGuid">Use the <see cref="ProjectTypes"/> collection for known guids.</param>
101+
public bool IsKind(string typeGuid)
102+
{
103+
ThreadHelper.ThrowIfNotOnUIThread();
104+
105+
if (Type == NodeType.Project || Type == NodeType.VirtualProject)
106+
{
107+
return _hierarchy.IsProjectOfType(typeGuid);
108+
}
109+
110+
return false;
111+
}
112+
113+
/// <summary>
114+
/// Converts the node a <see cref="EnvDTE.Project"/>.
115+
/// </summary>
116+
public EnvDTE.Project? ToProject()
117+
{
118+
return HierarchyUtilities.GetProject(Item);
119+
}
120+
121+
/// <summary>
122+
/// Converts the node a <see cref="EnvDTE.ProjectItem"/>.
123+
/// </summary>
124+
public EnvDTE.ProjectItem? ToProjectItem()
125+
{
126+
ThreadHelper.ThrowIfNotOnUIThread();
127+
128+
if (_hierarchy.TryGetItemProperty(_itemId, (int)__VSHPROPID.VSHPROPID_ExtObject, out object? obj))
129+
{
130+
return obj as EnvDTE.ProjectItem;
131+
}
132+
133+
return null;
134+
}
135+
136+
/// <summary>
137+
/// Creates a new instance based on a hierarchy.
138+
/// </summary>
139+
public static async Task<ItemNode?> CreateAsync(IVsHierarchy hierarchy, uint itemId)
140+
{
141+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
142+
IVsHierarchyItem? item = await hierarchy.ToHierarcyItemAsync(itemId);
143+
144+
return Create(item);
145+
}
146+
147+
/// <summary>
148+
/// Creates a new instance based on a hierarchy item.
149+
/// </summary>
150+
public static ItemNode? Create(IVsHierarchyItem? item)
151+
{
152+
if (item == null)
153+
{
154+
return null;
155+
}
156+
157+
return new ItemNode(item);
158+
}
159+
160+
private NodeType GetNodeType(IVsHierarchyItemIdentity identity)
161+
{
162+
if (HierarchyUtilities.IsSolutionNode(identity))
163+
{
164+
return NodeType.Solution;
165+
}
166+
else if (HierarchyUtilities.IsSolutionFolder(identity))
167+
{
168+
return NodeType.SolutionFolder;
169+
}
170+
else if (HierarchyUtilities.IsMiscellaneousProject(identity))
171+
{
172+
return NodeType.MiscProject;
173+
}
174+
else if (HierarchyUtilities.IsVirtualProject(identity))
175+
{
176+
return NodeType.VirtualProject;
177+
}
178+
else if (HierarchyUtilities.IsProject(identity))
179+
{
180+
return NodeType.Project;
181+
}
182+
else if (HierarchyUtilities.IsPhysicalFile(identity))
183+
{
184+
return NodeType.PhysicalFile;
185+
}
186+
else if (HierarchyUtilities.IsPhysicalFolder(identity))
187+
{
188+
return NodeType.PhysicalFolder;
189+
}
190+
191+
return NodeType.Unknown;
192+
}
193+
}
194+
195+
/// <summary>
196+
/// Types of nodes.
197+
/// </summary>
198+
public enum NodeType
199+
{
200+
/// <summary>Physical file on disk</summary>
201+
PhysicalFile,
202+
/// <summary>Physical folder on disk</summary>
203+
PhysicalFolder,
204+
/// <summary>A project</summary>
205+
Project,
206+
/// <summary>A miscellaneous project</summary>
207+
MiscProject,
208+
/// <summary>A virtual project</summary>
209+
VirtualProject,
210+
/// <summary>The solution</summary>
211+
Solution,
212+
/// <summary>A solution folder</summary>
213+
SolutionFolder,
214+
/// <summary>Unknown node type</summary>
215+
Unknown,
216+
}
217+
}

0 commit comments

Comments
 (0)