/* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Apache License, Version 2.0. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Apache License, Version 2.0, please send an email to * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Apache License, Version 2.0. * * You must not remove this notice, or any other, from this software. * * ***************************************************************************/ using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Diagnostics; using System.Threading; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using VSConstants = Microsoft.VisualStudio.VSConstants; namespace Microsoft.VisualStudio.Navigation { /// /// Single node inside the tree of the libraries in the object browser or class view. /// public class LibraryNode : SimpleObjectList, IVsNavInfoNode, ISimpleObject { private string _name, _fullname; private LibraryNodeCapabilities _capabilities; private readonly LibraryNodeType _type; private readonly CommandID _contextMenuID; private readonly string _tooltip; private readonly Dictionary _filteredView; private readonly Dictionary _childrenByName; private bool _duplicatedByName; public LibraryNode(string name, string fullname, LibraryNodeType type) : this(name, fullname, type, LibraryNodeCapabilities.None, null) { } public LibraryNode(string name, string fullname, LibraryNodeType type, LibraryNodeCapabilities capabilities, CommandID contextMenuID) { Debug.Assert(name != null); _capabilities = capabilities; _contextMenuID = contextMenuID; _name = name; _fullname = fullname; _tooltip = name; _type = type; _filteredView = new Dictionary(); _childrenByName = new Dictionary(); } protected LibraryNode(LibraryNode node) : this(node, node.FullName) { } protected LibraryNode(LibraryNode node, string newFullName) { _capabilities = node._capabilities; _contextMenuID = node._contextMenuID; _name = node._name; _tooltip = node._tooltip; _type = node._type; _fullname = newFullName; Children.AddRange(node.Children); _childrenByName = new Dictionary(node._childrenByName); _filteredView = new Dictionary(); } protected void SetCapabilityFlag(LibraryNodeCapabilities flag, bool value) { if (value) { _capabilities |= flag; } else { _capabilities &= ~flag; } } /// /// Get or Set if the node can be deleted. /// public bool CanDelete { get { return (0 != (_capabilities & LibraryNodeCapabilities.AllowDelete)); } set { SetCapabilityFlag(LibraryNodeCapabilities.AllowDelete, value); } } /// /// Get or Set if the node can be associated with some source code. /// public bool CanGoToSource { get { return (0 != (_capabilities & LibraryNodeCapabilities.HasSourceContext)); } set { SetCapabilityFlag(LibraryNodeCapabilities.HasSourceContext, value); } } /// /// Get or Set if the node can be renamed. /// public bool CanRename { get { return (0 != (_capabilities & LibraryNodeCapabilities.AllowRename)); } set { SetCapabilityFlag(LibraryNodeCapabilities.AllowRename, value); } } /// /// /// public override uint Capabilities { get { return (uint)_capabilities; } } public string TooltipText { get { return _tooltip; } } public void AddNode(LibraryNode node) { lock (Children) { Children.Add(node); LibraryNode[] nodes; if (!_childrenByName.TryGetValue(node.Name, out nodes)) { // common case, no duplicates by name _childrenByName[node.Name] = new[] { node }; } else { // uncommon case, duplicated by name _childrenByName[node.Name] = nodes = nodes.Append(node); foreach (var dupNode in nodes) { dupNode.DuplicatedByName = true; } } } Update(); } public void RemoveNode(LibraryNode node) { if (node != null) { lock (Children) { Children.Remove(node); LibraryNode[] items; if (_childrenByName.TryGetValue(node.Name, out items)) { if (items.Length == 1) { System.Diagnostics.Debug.Assert(items[0] == node); _childrenByName.Remove(node.Name); } else { var newItems = new LibraryNode[items.Length - 1]; for (int i = 0, write = 0; i < items.Length; i++) { if (items[i] != node) { newItems[write++] = items[i]; } } _childrenByName[node.Name] = newItems; } } } Update(); } } public virtual object BrowseObject { get { return null; } } public override uint CategoryField(LIB_CATEGORY category) { uint fieldValue = 0; switch (category) { case (LIB_CATEGORY)_LIB_CATEGORY2.LC_PHYSICALCONTAINERTYPE: fieldValue = (uint)_LIBCAT_PHYSICALCONTAINERTYPE.LCPT_PROJECT; break; case LIB_CATEGORY.LC_NODETYPE: fieldValue = (uint)_LIBCAT_NODETYPE.LCNT_HIERARCHY; break; case LIB_CATEGORY.LC_LISTTYPE: { LibraryNodeType subTypes = LibraryNodeType.None; foreach (LibraryNode node in Children) { subTypes |= node._type; } fieldValue = (uint)subTypes; } break; case (LIB_CATEGORY)_LIB_CATEGORY2.LC_HIERARCHYTYPE: fieldValue = (uint)_LIBCAT_HIERARCHYTYPE.LCHT_UNKNOWN; break; default: throw new NotImplementedException(); } return fieldValue; } public virtual LibraryNode Clone() { return new LibraryNode(this); } public virtual LibraryNode Clone(string newFullName) { return new LibraryNode(this, newFullName); } /// /// Performs the operations needed to delete this node. /// public virtual void Delete() { } /// /// Perform a Drag and Drop operation on this node. /// public virtual void DoDragDrop(OleDataObject dataObject, uint keyState, uint effect) { } public virtual uint EnumClipboardFormats(_VSOBJCFFLAGS flags, VSOBJCLIPFORMAT[] formats) { return 0; } public virtual void FillDescription(_VSOBJDESCOPTIONS flags, IVsObjectBrowserDescription3 description) { description.ClearDescriptionText(); description.AddDescriptionText3(_name, VSOBDESCRIPTIONSECTION.OBDS_NAME, null); } public IVsSimpleObjectList2 FilterView(uint filterType) { var libraryNodeType = (LibraryNodeType)filterType; LibraryNode filtered = null; if (_filteredView.TryGetValue(libraryNodeType, out filtered)) { return filtered as IVsSimpleObjectList2; } filtered = this.Clone(); for (int i = 0; i < filtered.Children.Count; ) { if (0 == (filtered.Children[i]._type & libraryNodeType)) { filtered.Children.RemoveAt(i); } else { i += 1; } } _filteredView.Add(libraryNodeType, filtered); return filtered as IVsSimpleObjectList2; } public virtual void GotoSource(VSOBJGOTOSRCTYPE gotoType) { // Do nothing. } public virtual string Name { get { return _name; } } public virtual string GetTextRepresentation(VSTREETEXTOPTIONS options) { return Name; } public LibraryNodeType NodeType { get { return _type; } } /// /// Finds the source files associated with this node. /// /// The hierarchy containing the items. /// The item id of the item. /// Number of items. public virtual void SourceItems(out IVsHierarchy hierarchy, out uint itemId, out uint itemsCount) { hierarchy = null; itemId = 0; itemsCount = 0; } public virtual void Rename(string newName, uint flags) { this._name = newName; } public virtual string UniqueName { get { return Name; } } public string FullName { get { return _fullname; } } public CommandID ContextMenuID { get { return _contextMenuID; } } public virtual StandardGlyphGroup GlyphType { get { return StandardGlyphGroup.GlyphGroupModule; } } public VSTREEDISPLAYDATA DisplayData { get { var res = new VSTREEDISPLAYDATA(); res.Image = res.SelectedImage = (ushort)GlyphType; return res; } } public virtual IVsSimpleObjectList2 DoSearch(VSOBSEARCHCRITERIA2 criteria) { return null; } /// /// Visit this node and its children. /// /// Visitor to invoke methods on when visiting the nodes. public void Visit(ILibraryNodeVisitor visitor, CancellationToken ct = default(CancellationToken)) { if (ct.IsCancellationRequested) { visitor.LeaveNode(this, ct); return; } if (visitor.EnterNode(this, ct)) { lock (Children) { foreach (var child in Children) { if (ct.IsCancellationRequested) { visitor.LeaveNode(this, ct); return; } child.Visit(visitor, ct); } } } visitor.LeaveNode(this, ct); } #region IVsNavInfoNode Members int IVsNavInfoNode.get_Name(out string pbstrName) { pbstrName = UniqueName; return VSConstants.S_OK; } int IVsNavInfoNode.get_Type(out uint pllt) { pllt = (uint)_type; return VSConstants.S_OK; } #endregion /// /// Enumeration of the capabilities of a node. It is possible to combine different values /// to support more capabilities. /// This enumeration is a copy of _LIB_LISTCAPABILITIES with the Flags attribute set. /// [Flags()] public enum LibraryNodeCapabilities { None = _LIB_LISTCAPABILITIES.LLC_NONE, HasBrowseObject = _LIB_LISTCAPABILITIES.LLC_HASBROWSEOBJ, HasDescriptionPane = _LIB_LISTCAPABILITIES.LLC_HASDESCPANE, HasSourceContext = _LIB_LISTCAPABILITIES.LLC_HASSOURCECONTEXT, HasCommands = _LIB_LISTCAPABILITIES.LLC_HASCOMMANDS, AllowDragDrop = _LIB_LISTCAPABILITIES.LLC_ALLOWDRAGDROP, AllowRename = _LIB_LISTCAPABILITIES.LLC_ALLOWRENAME, AllowDelete = _LIB_LISTCAPABILITIES.LLC_ALLOWDELETE, AllowSourceControl = _LIB_LISTCAPABILITIES.LLC_ALLOWSCCOPS, } public bool DuplicatedByName { get { return _duplicatedByName; } private set { _duplicatedByName = value; } } } /// /// Enumeration of the possible types of node. The type of a node can be the combination /// of one of more of these values. /// This is actually a copy of the _LIB_LISTTYPE enumeration with the difference that the /// Flags attribute is set so that it is possible to specify more than one value. /// [Flags()] public enum LibraryNodeType { None = 0, Hierarchy = _LIB_LISTTYPE.LLT_HIERARCHY, Namespaces = _LIB_LISTTYPE.LLT_NAMESPACES, Classes = _LIB_LISTTYPE.LLT_CLASSES, Members = _LIB_LISTTYPE.LLT_MEMBERS, Package = _LIB_LISTTYPE.LLT_PACKAGE, PhysicalContainer = _LIB_LISTTYPE.LLT_PHYSICALCONTAINERS, Containment = _LIB_LISTTYPE.LLT_CONTAINMENT, ContainedBy = _LIB_LISTTYPE.LLT_CONTAINEDBY, UsesClasses = _LIB_LISTTYPE.LLT_USESCLASSES, UsedByClasses = _LIB_LISTTYPE.LLT_USEDBYCLASSES, NestedClasses = _LIB_LISTTYPE.LLT_NESTEDCLASSES, InheritedInterface = _LIB_LISTTYPE.LLT_INHERITEDINTERFACES, InterfaceUsedByClasses = _LIB_LISTTYPE.LLT_INTERFACEUSEDBYCLASSES, Definitions = _LIB_LISTTYPE.LLT_DEFINITIONS, References = _LIB_LISTTYPE.LLT_REFERENCES, DeferExpansion = _LIB_LISTTYPE.LLT_DEFEREXPANSION, } /// /// Visitor interface used to enumerate all s in the library. /// public interface ILibraryNodeVisitor { /// /// Called on each node before any of its child nodes are visited. /// /// The node that is being visited. /// true if children of this node should be visited, otherwise false. bool EnterNode(LibraryNode node, CancellationToken ct); /// /// Called on each node after all its child nodes were visited. /// /// The node that was being visited. void LeaveNode(LibraryNode node, CancellationToken ct); } }