private HierarchyItem CreateItem(string fileName, HierarchyItemType itemType, HierarchyNode node) { HierarchyItem parent = this.ancestors.Count > 0 ? this.ancestors.Peek() : null; var result = new HierarchyItem(fileName, itemType, node.Caption, parent); return(result); }
private HierarchyItem VisitHierarchyNode(HierarchyNode node) { HierarchyItem result = null; IVsHierarchy hierarchy = node.Hierarchy; Guid itemType = node.ItemType; if (itemType == VSConstants.GUID_ItemType_PhysicalFile) { string canonicalName = node.CanonicalName; if (!string.IsNullOrEmpty(canonicalName)) { result = this.CreateItem(canonicalName, HierarchyItemType.File, node); } } else { IVsSolution solution = hierarchy as IVsSolution; if (solution != null) { string directory, file, options; int hr = solution.GetSolutionInfo(out directory, out file, out options); if (ErrorHandler.Succeeded(hr) && !string.IsNullOrEmpty(directory) && !string.IsNullOrEmpty(file)) { result = this.CreateItem(Path.Combine(directory, file), HierarchyItemType.Solution, node); } } else { IVsProject project = hierarchy as IVsProject; if (project != null) { // For some reason, physical folders (like Properties) also implement IVsProject. if (itemType != VSConstants.GUID_ItemType_PhysicalFolder) { string projectFile; int hr = project.GetMkDocument(node.ItemId, out projectFile); if (ErrorHandler.Succeeded(hr)) { result = this.CreateItem(projectFile, HierarchyItemType.Project, node); } } } } } return(result); }
public bool AddHierarchyItem(HierarchyItem item) { if (this.hierarchyItems == EmptySet) { this.hierarchyItems = new HashSet <HierarchyItem>(); } bool result = this.hierarchyItems.Add(item); if (result) { this.projectNames = null; } return(result); }
public HierarchyItem(string fileName, HierarchyItemType itemType, string caption, HierarchyItem parent) { this.FileName = fileName; this.ItemType = itemType; // Note: Solution captions can contain the Unicode Left-To-Right Order Mark (0x200E) character. // It doesn't hurt anything usually, but it can show up as ? if it's incorrectly decoded. this.Caption = caption; this.Parent = parent; this.Level = parent != null ? parent.Level + 1 : 0; }
/// <summary> /// Enumerates over the hierarchy items for the given hierarchy traversing into nested hierarchies. /// </summary> /// <param name="hierarchy">hierarchy to enumerate over.</param> /// <param name="itemid">item id of the hierarchy</param> /// <param name="recursionLevel">Depth of recursion. e.g. if recursion started with the Solution /// node, then : Level 0 -- Solution node, Level 1 -- children of Solution, etc.</param> /// <param name="visibleNodesOnly">true if only nodes visible in the Solution Explorer should /// be traversed. false if all project items should be traversed.</param> private void VisitHierarchyNodes(HierarchyNode node, int recursionLevel, bool visibleNodesOnly) { // Note: This code originated from "Solution Hierarchy Traversal Sample (C#)" // https://msdn.microsoft.com/en-us/library/bb165347(v=vs.80).aspx // In C:\Setups\Microsoft\Visual Studio\VS 2005\Visual Studio 2005 SDK\ ... // VisualStudioIntegration\Samples\Project\CSharp\Example.SolutionHierarchyTraversal // // Check first if this node has a nested hierarchy. If so, then there really are two // identities for this node: 1. hierarchy/itemid and 2. nestedHierarchy/nestedItemId. // We will recurse and call VisitHierarchyNodes which will traverse this node using // the inner nestedHierarchy/nestedItemId identity. Basically, if this returns a // nested hierarchy, then the current node is just a shortcut to the nested hierarchy. HierarchyNode nestedNode; if (node.TryGetNestedHierarchy(out nestedNode)) { this.VisitHierarchyNodes(nestedNode, recursionLevel, visibleNodesOnly); } else { // In VS 2015 and earlier, the Solution node enumerates ALL projects (including nested projects) // when asking for FirstChild/NextSibling, but it doesn't do that for FirstVisibleChild/NextVisibleSibling. // VS treats the actual hierarchy differently than the visible hierarchy, and the solution contains // shortcuts to all the projects in the actual hierarchy. So if we're not restricted to visible nodes, // then we can encounter nested projects twice as we traverse the hierarchy. We'll make sure // we don't traverse through the same project twice. However, we can't restrict to visible items // because we need to ensure that we get the "Miscellaneous Files" (e.g., external files opened // in the solution), which may not be visible in the Solution Explorer. // // Note: currentItem can be null if we're visiting a physical folder (e.g., a Properties folder), a // virtual folder (e.g., Solution Items or Miscellaneous Files), or some other node type that is // not a solution, project or file type. HierarchyItem currentItem = this.VisitHierarchyNode(node); bool visitChildren = true; if (currentItem != null) { visitChildren = currentItem.ItemType != HierarchyItemType.Project || !this.visitedProjects.Contains(currentItem.FileName); if (visitChildren) { this.items.Add(currentItem); } } if (visitChildren) { // Note: We'll push a null parent for miscellaneous files since they're not directly referenced by the solution. bool pushCurrentItemAsAncestor = (currentItem != null && currentItem.IsContainer) || (currentItem == null && node.ItemType == VSConstants.GUID_ItemType_VirtualFolder && node.CanonicalName == "Miscellaneous Files"); if (pushCurrentItemAsAncestor) { this.ancestors.Push(currentItem); } try { recursionLevel++; List <HierarchyNode> children = node.GetChildren(visibleNodesOnly).ToList(); foreach (HierarchyNode child in children) { this.VisitHierarchyNodes(child, recursionLevel, visibleNodesOnly); } } finally { if (pushCurrentItemAsAncestor) { this.ancestors.Pop(); } } if (currentItem != null && currentItem.ItemType == HierarchyItemType.Project) { this.visitedProjects.Add(currentItem.FileName); } } } }