/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); return(this.Project.ProjectNode.Site.GetUIThread().Invoke <EnvDTE.ProjectItem>(() => { var proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (var scope = new AutomationScope(this.Project.ProjectNode.Site)) { var result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string realPath = null; if (op != VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE) { var fileName = Path.GetFileName(path); var fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); realPath = Path.Combine(fileDirectory, fileName); } else { realPath = path; } itemAdded = this.EvaluateAddResult(result[0], realPath); } return itemAdded; })); }
/// <summary> /// Gets a value indicating whether the project item is open in a particular view type. /// </summary> /// <param name="viewKind">A Constants.vsViewKind* indicating the type of view to check./param> /// <returns>A Boolean value indicating true if the project is open in the given view type; false if not. </returns> public override bool get_IsOpen(string viewKind) { CheckProjectIsValid(); // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } bool isOpen = false; using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { IVsUIHierarchy hier; uint itemid; IVsWindowFrame windowFrame; isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); }); } return(isOpen); }
/// <summary> /// Adds a folder to the collection of ProjectItems with the given name. /// /// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder. /// Virtual folders are not supported by this implementation. /// </summary> /// <param name="name">The name of the new folder to add</param> /// <param name="kind">A string representing a Guid of the folder kind.</param> /// <returns>A ProjectItem representing the newly added folder.</returns> public override ProjectItem AddFolder(string name, string kind) { Project.CheckProjectIsValid(); //Verify name is not null or empty Utilities.ValidateFileName(this.Project.ProjectNode.Site, name); //Verify that kind is null, empty, or a physical folder if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) { throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind"); } var existingChild = this.NodeWithItems.FindImmediateChildByName(name); if (existingChild != null) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name)); } ProjectNode proj = this.Project.ProjectNode; HierarchyNode newFolder = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { //In the case that we are adding a folder to a folder, we need to build up //the path to the project node. name = Path.Combine(NodeWithItems.FullPathToChildren, name); newFolder = proj.CreateFolderNodes(name); } return(newFolder.GetAutomationObject() as ProjectItem); }
/// <summary> /// Creates a new project item from an existing item template file and adds it to the project. /// </summary> /// <param name="fileName">The full path and file name of the template project file.</param> /// <param name="name">The file name to use for the new project item.</param> /// <returns>A ProjectItem object. </returns> public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { CheckProjectIsValid(); ProjectNode proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { // Determine the operation based on the extension of the filename. // We should run the wizard only if the extension is vstemplate // otherwise it's a clone operation VSADDITEMOPERATION op; Project.ProjectNode.Site.GetUIThread().Invoke(() => { if (Utilities.IsTemplateFile(fileName)) { op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; } else { op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; } VSADDRESULT[] result = new VSADDRESULT[1]; // It is not a very good idea to throw since the AddItem might return Cancel or Abort. // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result)); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string templateFilePath = System.IO.Path.Combine(fileDirectory, name); itemAdded = this.EvaluateAddResult(result[0], templateFilePath); }); } return itemAdded; }
/// <summary> /// Gets a value indicating whether the project item is open in a particular view type. /// </summary> /// <param name="viewKind">A Constants.vsViewKind* indicating the type of view to check./param> /// <returns>A Boolean value indicating true if the project is open in the given view type; false if not. </returns> public override bool get_IsOpen(string viewKind) { CheckProjectIsValid(); // Validate input params var logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(string.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid), nameof(viewKind)); } var isOpen = false; using (var scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.Node.ProjectMgr.Site.GetUIThread().Invoke(() => { isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out var hier, out var itemid, out var windowFrame); }); } return(isOpen); }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { Node.ProjectMgr.Site.GetUIThread().Invoke(() => this.node.Remove(true)); } }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { Node.ProjectMgr.Site.GetUIThread().Invoke(() => node.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder)); } }
/// <summary> /// Removes the project item from hierarchy. /// </summary> public virtual void Remove() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Invoke(() => this.node.Remove(false)); } }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => this.node.Remove(true)); } }
/// <summary> /// Opens the file item in the specified view. /// </summary> /// <param name="ViewKind">Specifies the view kind in which to open the item (file)</param> /// <returns>Window object</returns> public override EnvDTE.Window Open(string viewKind) { CheckProjectIsValid(); IVsWindowFrame windowFrame = null; var docData = IntPtr.Zero; using (var scope = new AutomationScope(this.Node.ProjectMgr.Site)) { this.Node.ProjectMgr.Site.GetUIThread().Invoke(() => { try { // Validate input params var logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(string.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid), "viewKind"); } uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; var rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (rdt == null) { throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); } ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.Node.Url, out ivsHierarchy, out itemid, out docData, out docCookie)); // Open the file using the IVsProject interface // We get the outer hierarchy so that projects can customize opening. var project = this.Node.ProjectMgr.GetOuterInterface <IVsProject>(); ErrorHandler.ThrowOnFailure(project.OpenItem(this.Node.ID, ref logicalViewGuid, docData, out windowFrame)); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } }); } // Get the automation object and return it return((windowFrame != null) ? VsShellUtilities.GetWindowObject(windowFrame) : null); }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { node.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder); }); } }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { ProjectNode.Site.GetUIThread().Invoke(() => { this.project.Remove(false); }); } }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { UIThread.Instance.RunSync(() => { this.project.Remove(false); }); } }
/// <summary> /// Creates a new project item from an existing item template file and adds it to the project. /// </summary> /// <param name="fileName">The full path and file name of the template project file.</param> /// <param name="name">The file name to use for the new project item.</param> /// <returns>A ProjectItem object. </returns> public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { CheckProjectIsValid(); var proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (var scope = new AutomationScope(this.Project.ProjectNode.Site)) { // Determine the operation based on the extension of the filename. // We should run the wizard only if the extension is vstemplate // otherwise it's a clone operation VSADDITEMOPERATION op; this.Project.ProjectNode.Site.GetUIThread().Invoke(() => { if (Utilities.IsTemplateFile(fileName)) { op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; } else { op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; } var result = new VSADDRESULT[1]; // It is not a very good idea to throw since the AddItem might return Cancel or Abort. // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result)); var fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); var templateFilePath = System.IO.Path.Combine(fileDirectory, name); itemAdded = this.EvaluateAddResult(result[0], templateFilePath); }); } return(itemAdded); }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); return(UIThread.Instance.RunSync <EnvDTE.ProjectItem>(() => { string ext = Path.GetExtension(path); foreach (var extension in this.Project.ProjectNode.CodeFileExtensions) { // http://pytools.codeplex.com/workitem/617 // We are currently in create project from existing code mode. The wizard walks all of the top-level // files and adds them. It then lets us handle any subdirectories by calling AddFromDirectory. // But we want to filter the files for both top-level and subdirectories. Therefore we derive from // PageManager and track when we're running the wizard and adding files for the wizard. If we are // currently adding them ignore anything other than a .py/.pyw files - returnning null is fine // here, the wizard doesn't care about the result. if (String.Compare(ext, extension, StringComparison.OrdinalIgnoreCase) == 0) { ProjectNode proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = System.IO.Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName); itemAdded = this.EvaluateAddResult(result[0], filePathInProject); } return itemAdded; } } return null; })); }
/// <summary> /// Saves or Save Asthe project. /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { Utilities.ArgumentNotNull("fileName", fileName); CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName)) { // Use the solution service to save the project file. Note that we have to use the service // so that all the shell's elements are aware that we are inside a save operation and // all the file change listenters registered by the shell are suspended. // Get the cookie of the project file from the RTD. IVsRunningDocumentTable rdt = this.project.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; Utilities.CheckNotNull(rdt); IVsHierarchy hier; uint itemid; IntPtr unkData; uint cookie; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, out itemid, out unkData, out cookie)); if (IntPtr.Zero != unkData) { Marshal.Release(unkData); } // Verify that we have a cookie. if (0 == cookie) { // This should never happen because if the project is open, then it must be in the RDT. throw new InvalidOperationException(); } // Get the IVsHierarchy for the project. IVsHierarchy prjHierarchy = project.GetOuterInterface <IVsHierarchy>(); // Now get the soulution. IVsSolution solution = this.project.Site.GetService(typeof(SVsSolution)) as IVsSolution; // Verify that we have both solution and hierarchy. Utilities.CheckNotNull(prjHierarchy); Utilities.CheckNotNull(solution); ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy, cookie)); } else { // We need to make some checks before we can call the save method on the project node. // This is mainly because it is now us and not the caller like in case of SaveAs or Save that should validate the file name. // The IPersistFileFormat.Save method only does a validation that is necessary to be performed. Example: in case of Save As the // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid) // 1. The file name has to be valid. string fullPath = fileName; try { fullPath = CommonUtils.GetAbsoluteFilePath(((ProjectNode)Project).ProjectFolder, fileName); } // We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted. catch (ArgumentException ex) { throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, fileName), ex); } // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path. // If we decide that this is performance critical then this should be refactored. Utilities.ValidateFileName(this.project.Site, fullPath); if (!isCalledFromSaveAs) { // 2. The file name has to be the same if (!CommonUtils.IsSamePath(fullPath, this.project.Url)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 1, 0)); } else { ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 0, 0)); } } } }
/// <summary> /// Saves or Save Asthe project. /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { Utilities.ArgumentNotNull("fileName", fileName); CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName)) { // Use the solution service to save the project file. Note that we have to use the service // so that all the shell's elements are aware that we are inside a save operation and // all the file change listenters registered by the shell are suspended. // Get the cookie of the project file from the RTD. IVsRunningDocumentTable rdt = this.project.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; Utilities.CheckNotNull(rdt); IVsHierarchy hier; uint itemid; IntPtr unkData; uint cookie; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, out itemid, out unkData, out cookie)); if (IntPtr.Zero != unkData) { Marshal.Release(unkData); } // Verify that we have a cookie. if (0 == cookie) { // This should never happen because if the project is open, then it must be in the RDT. throw new InvalidOperationException(); } // Get the IVsHierarchy for the project. IVsHierarchy prjHierarchy = project.GetOuterInterface<IVsHierarchy>(); // Now get the soulution. IVsSolution solution = this.project.Site.GetService(typeof(SVsSolution)) as IVsSolution; // Verify that we have both solution and hierarchy. Utilities.CheckNotNull(prjHierarchy); Utilities.CheckNotNull(solution); ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy, cookie)); } else { // We need to make some checks before we can call the save method on the project node. // This is mainly because it is now us and not the caller like in case of SaveAs or Save that should validate the file name. // The IPersistFileFormat.Save method only does a validation that is necessary to be performed. Example: in case of Save As the // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid) // 1. The file name has to be valid. string fullPath = fileName; try { fullPath = CommonUtils.GetAbsoluteFilePath(((ProjectNode)Project).ProjectFolder, fileName); } // We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted. catch (ArgumentException ex) { throw new InvalidOperationException(String.Format(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture), fileName), ex); } // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path. // If we decide that this is performance critical then this should be refactored. Utilities.ValidateFileName(this.project.Site, fullPath); if (!isCalledFromSaveAs) { // 2. The file name has to be the same if (!CommonUtils.IsSamePath(fullPath, this.project.Url)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 1, 0)); } else { ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 0, 0)); } } } }
/// <summary> /// Removes the project item from hierarchy. /// </summary> public virtual void Remove() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Invoke(() => this.node.Remove(false)); } }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => this.node.Remove(true)); } }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { UIThread.Instance.RunSync(() => { this.project.Remove(false); }); } }
/// <summary> /// Adds a folder to the collection of ProjectItems with the given name. /// /// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder. /// Virtual folders are not supported by this implementation. /// </summary> /// <param name="name">The name of the new folder to add</param> /// <param name="kind">A string representing a Guid of the folder kind.</param> /// <returns>A ProjectItem representing the newly added folder.</returns> public override ProjectItem AddFolder(string name, string kind) { Project.CheckProjectIsValid(); //Verify name is not null or empty Utilities.ValidateFileName(this.Project.ProjectNode.Site, name); //Verify that kind is null, empty, or a physical folder if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) { throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind"); } return Project.ProjectNode.Site.GetUIThread().Invoke<EnvDTE.ProjectItem>(() => { var existingChild = this.NodeWithItems.FindImmediateChildByName(name); if (existingChild != null) { if (existingChild.IsNonMemberItem && ErrorHandler.Succeeded(existingChild.IncludeInProject(false))) { return existingChild.GetAutomationObject() as ProjectItem; } throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name)); } ProjectNode proj = this.Project.ProjectNode; HierarchyNode newFolder = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { //In the case that we are adding a folder to a folder, we need to build up //the path to the project node. name = Path.Combine(NodeWithItems.FullPathToChildren, name); newFolder = proj.CreateFolderNodes(name); } return newFolder.GetAutomationObject() as ProjectItem; }); }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); return Project.ProjectNode.Site.GetUIThread().Invoke<EnvDTE.ProjectItem>(() => { ProjectNode proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string realPath = null; if (op != VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE) { string fileName = Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); realPath = Path.Combine(fileDirectory, fileName); } else { realPath = path; } itemAdded = this.EvaluateAddResult(result[0], realPath); } return itemAdded; }); }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { node.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder); }); } }
/// <summary> /// Saves or Save As the file /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { Utilities.ArgumentNotNull("fileName", fileName); CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { IntPtr docData = IntPtr.Zero; try { IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (rdt == null) { throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); } // First we see if someone else has opened the requested view of the file. uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; int canceled; string url = this.Node.Url; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, url, out ivsHierarchy, out itemid, out docData, out docCookie)); // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && fileName.Length == 0) { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, url, this.Node.ID, docData, out canceled)); } else { Utilities.ValidateFileName(this.Node.ProjectMgr.Site, fileName); // Compute the fullpath from the directory of the existing Url. string fullPath = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(url), fileName); if (!isCalledFromSaveAs) { if (!CommonUtils.IsSamePath(this.Node.Url, fullPath)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } else { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } } if (canceled == 1) { throw new InvalidOperationException(); } } catch (COMException e) { throw new InvalidOperationException(e.Message); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } }); } }
/// <summary> /// Removes the project from the current solution. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.project.Site)) { ProjectNode.Site.GetUIThread().Invoke(() => { this.project.Remove(false); }); } }
/// <summary> /// Adds an item to the project. /// </summary> /// <param name="path">The full path of the item to add.</param> /// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param> /// <returns>A ProjectItem object. </returns> protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { CheckProjectIsValid(); return UIThread.Instance.RunSync<EnvDTE.ProjectItem>(() => { string ext = Path.GetExtension(path); foreach (var extension in this.Project.ProjectNode.CodeFileExtensions) { // http://pytools.codeplex.com/workitem/617 // We are currently in create project from existing code mode. The wizard walks all of the top-level // files and adds them. It then lets us handle any subdirectories by calling AddFromDirectory. // But we want to filter the files for both top-level and subdirectories. Therefore we derive from // PageManager and track when we're running the wizard and adding files for the wizard. If we are // currently adding them ignore anything other than a .py/.pyw files - returnning null is fine // here, the wizard doesn't care about the result. if (String.Compare(ext, extension, StringComparison.OrdinalIgnoreCase) == 0) { ProjectNode proj = this.Project.ProjectNode; EnvDTE.ProjectItem itemAdded = null; using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { VSADDRESULT[] result = new VSADDRESULT[1]; ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); string fileName = System.IO.Path.GetFileName(path); string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName); itemAdded = this.EvaluateAddResult(result[0], filePathInProject); } return itemAdded; } } return null; }); }
/// <summary> /// Expands the view of Solution Explorer to show project items. /// </summary> public virtual void ExpandView() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { Node.ProjectMgr.Site.GetUIThread().Invoke(() => node.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder)); } }
/// <summary> /// Removes the item from its project and its storage. /// </summary> public virtual void Delete() { CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { Node.ProjectMgr.Site.GetUIThread().Invoke(() => this.node.Remove(true)); } }
/// <summary> /// Opens the file item in the specified view. /// </summary> /// <param name="ViewKind">Specifies the view kind in which to open the item (file)</param> /// <returns>Window object</returns> public override EnvDTE.Window Open(string viewKind) { CheckProjectIsValid(); IVsWindowFrame windowFrame = null; IntPtr docData = IntPtr.Zero; using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { try { // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (rdt == null) { throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); } ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.Node.Url, out ivsHierarchy, out itemid, out docData, out docCookie)); // Open the file using the IVsProject interface // We get the outer hierarchy so that projects can customize opening. var project = Node.ProjectMgr.GetOuterInterface<IVsProject>(); ErrorHandler.ThrowOnFailure(project.OpenItem(Node.ID, ref logicalViewGuid, docData, out windowFrame)); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } }); } // Get the automation object and return it return ((windowFrame != null) ? VsShellUtilities.GetWindowObject(windowFrame) : null); }
/// <summary> /// Gets a value indicating whether the project item is open in a particular view type. /// </summary> /// <param name="viewKind">A Constants.vsViewKind* indicating the type of view to check./param> /// <returns>A Boolean value indicating true if the project is open in the given view type; false if not. </returns> public override bool get_IsOpen(string viewKind) { CheckProjectIsValid(); // Validate input params Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; try { if (!(String.IsNullOrEmpty(viewKind))) { logicalViewGuid = new Guid(viewKind); } } catch (FormatException) { // Not a valid guid throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid, CultureInfo.CurrentUICulture), "viewKind"); } bool isOpen = false; using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { IVsUIHierarchy hier; uint itemid; IVsWindowFrame windowFrame; isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); }); } return isOpen; }
/// <summary> /// Saves or Save As the file /// </summary> /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param> /// <param name="fileName">The name of the project file.</param> private void DoSave(bool isCalledFromSaveAs, string fileName) { Utilities.ArgumentNotNull("fileName", fileName); CheckProjectIsValid(); using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { UIThread.Instance.RunSync(() => { IntPtr docData = IntPtr.Zero; try { IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; if (rdt == null) { throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); } // First we see if someone else has opened the requested view of the file. uint itemid; IVsHierarchy ivsHierarchy; uint docCookie; int canceled; string url = this.Node.Url; ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, url, out ivsHierarchy, out itemid, out docData, out docCookie)); // If an empty file name is passed in for Save then make the file name the project name. if (!isCalledFromSaveAs && fileName.Length == 0) { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, url, this.Node.ID, docData, out canceled)); } else { Utilities.ValidateFileName(this.Node.ProjectMgr.Site, fileName); // Compute the fullpath from the directory of the existing Url. string fullPath = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(url), fileName); if (!isCalledFromSaveAs) { if (!CommonUtils.IsSamePath(this.Node.Url, fullPath)) { throw new InvalidOperationException(); } ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } else { ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); } } if (canceled == 1) { throw new InvalidOperationException(); } } catch (COMException e) { throw new InvalidOperationException(e.Message); } finally { if (docData != IntPtr.Zero) { Marshal.Release(docData); } } }); } }