/* **************************************************************************** * * 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.Diagnostics; using System.IO; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; using VSConstants = Microsoft.VisualStudio.VSConstants; namespace Microsoft.VisualStudio.Project { public class CommonFolderNode : FolderNode { private CommonProjectNode _project; public CommonFolderNode(CommonProjectNode root, ProjectElement element) : base(root, element) { _project = root; } public override bool IsNonMemberItem { get { return ItemNode is AllFilesProjectElement; } } public override object GetIconHandle(bool open) { if (ItemNode.IsExcluded) { return this.ProjectMgr.ImageHandler.GetIconHandle(open ? (int)ProjectNode.ImageName.OpenExcludedFolder : (int)ProjectNode.ImageName.ExcludedFolder); } return base.GetIconHandle(open); } public override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { //Hide Exclude from Project command, show everything else normal Folder node supports if (cmdGroup == Microsoft.VisualStudio.Project.VsMenus.guidStandardCommandSet2K) { switch ((VsCommands2K)cmd) { case VsCommands2K.EXCLUDEFROMPROJECT: if (ItemNode.IsExcluded) { result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE; return VSConstants.S_OK; } break; case VsCommands2K.INCLUDEINPROJECT: if (ItemNode.IsExcluded) { result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; return VSConstants.S_OK; } break; case CommonConstants.OpenFolderInExplorerCmdId: result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; return VSConstants.S_OK; } } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { switch ((SharedCommands)cmd) { case SharedCommands.AddExistingFolder: result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; return VSConstants.S_OK; } } return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); } public override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { if (cmdGroup == Microsoft.VisualStudio.Project.VsMenus.guidStandardCommandSet2K) { if ((VsCommands2K)cmd == CommonConstants.OpenFolderInExplorerCmdId) { Process.Start(this.Url); return VSConstants.S_OK; } } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { switch ((SharedCommands)cmd) { case SharedCommands.AddExistingFolder: return ProjectMgr.AddExistingFolderToNode(this); } } return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut); } /// /// Handles the exclude from project command. /// /// public override int ExcludeFromProject() { Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr"); if (!ProjectMgr.QueryEditProjectFile(false) || !ProjectMgr.QueryFolderRemove(Parent, Url)) { return VSConstants.E_FAIL; } for (var child = FirstChild; child != null; child = child.NextSibling) { // we automatically exclude all children below us too int hr = child.ExcludeFromProject(); if (ErrorHandler.Failed(hr)) { return hr; } } ResetNodeProperties(); ItemNode.RemoveFromProjectFile(); if (!Directory.Exists(CommonUtils.TrimEndSeparator(Url))) { Parent.RemoveChild(this); ProjectMgr.OnItemDeleted(this); } else { ItemNode = new AllFilesProjectElement(Url, ItemNode.ItemTypeName, ProjectMgr); if (!ProjectMgr.IsShowingAllFiles) { IsVisible = false; ProjectMgr.OnInvalidateItems(Parent); } ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); } return VSConstants.S_OK; } public override int IncludeInProject(bool includeChildren) { if (Parent.ItemNode != null && Parent.ItemNode.IsExcluded) { // if our parent is excluded it needs to first be included int hr = Parent.IncludeInProject(false); if (ErrorHandler.Failed(hr)) { return hr; } } if (!ProjectMgr.QueryEditProjectFile(false) || !ProjectMgr.QueryFolderAdd(Parent, Url)) { return VSConstants.E_FAIL; } ResetNodeProperties(); ItemNode = ProjectMgr.CreateMsBuildFileItem( CommonUtils.GetRelativeDirectoryPath(ProjectMgr.ProjectHome, Url), ProjectFileConstants.Folder ); IsVisible = true; if (includeChildren) { for (var child = FirstChild; child != null; child = child.NextSibling) { // we automatically include all children below us too int hr = child.IncludeInProject(includeChildren); if (ErrorHandler.Failed(hr)) { return hr; } } } ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); return VSConstants.S_OK; } public override void RenameFolder(string newName) { _project.SuppressFileChangeNotifications(); try { base.RenameFolder(newName); } finally { _project.RestoreFileChangeNotifications(); } if (ProjectMgr.TryDeactivateSymLinkWatcher(this)) { ProjectMgr.CreateSymLinkWatcher(Url); } } public override void Remove(bool removeFromStorage) { base.Remove(removeFromStorage); // if we were a symlink folder, we need to stop watching now. ProjectMgr.TryDeactivateSymLinkWatcher(this); } public override void Close() { base.Close(); // make sure this thing isn't hanging around... ProjectMgr.TryDeactivateSymLinkWatcher(this); } /// /// Common Folder Node can only be deleted from file system. /// public override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage; } #if DEV11_OR_LATER public override object GetProperty(int propId) { CommonFolderNode.BoldStartupOnIcon(propId, this); return base.GetProperty(propId); } #else public override int SetProperty(int propid, object value) { BoldStartupOnExpand(propid, this); return base.SetProperty(propid, value); } public static void BoldStartupOnExpand(int propId, HierarchyNode parent) { // We can't bold the startup item while we're loading the project because the // UI hierarchy isn't initialized yet. So instead we wait until we get a request // for an icon for the startup item's parent, and then we bold it. if (propId == (int)__VSHPROPID.VSHPROPID_Expanded) { SetBoldStartup(parent); } } #endif public static void BoldStartupOnIcon(int propId, HierarchyNode parent) { // We can't bold the startup item while we're loading the project because the // UI hierarchy isn't initialized yet. So instead we wait until we get a request // for an icon for the startup item's parent, and then we bold it. if (propId == (int)__VSHPROPID.VSHPROPID_IconIndex || propId == (int)__VSHPROPID.VSHPROPID_OpenFolderIconIndex) { SetBoldStartup(parent); } } private static void SetBoldStartup(HierarchyNode parent) { string startupFile; CommonProjectNode comProj = (CommonProjectNode)parent.ProjectMgr; HierarchyNode startupItem; if (!comProj._boldedStartupItem && (startupFile = comProj.GetStartupFile()) != null && (startupItem = parent.ProjectMgr.FindNodeByFullPath(CommonUtils.GetAbsoluteFilePath(comProj.ProjectFolder, startupFile))) != null) { // we're expanding the parent of the comProj.BoldStartupItem(startupItem); } } public new CommonProjectNode ProjectMgr { get { return (CommonProjectNode)base.ProjectMgr; } } } }