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