/// <summary> /// Maps back to the hierarchy or project item object corresponding to the browse object. /// </summary> /// <param name="hier">Reference to the hierarchy object.</param> /// <param name="itemid">Reference to the project item.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public virtual int GetProjectItem(out IVsHierarchy hier, out uint itemid) { Utilities.CheckNotNull(this.project); Utilities.CheckNotNull(this.project.NodeProperties); return(this.project.NodeProperties.GetProjectItem(out hier, out itemid)); }
/// <summary> /// Links a reference node to the project and hierarchy. /// </summary> public virtual void AddReference() { ProjectMgr.Site.GetUIThread().MustBeCalledFromUIThread(); ReferenceContainerNode referencesFolder = this.ProjectMgr.GetReferenceContainer() as ReferenceContainerNode; Utilities.CheckNotNull(referencesFolder, "Could not find the References node"); CannotAddReferenceErrorMessage referenceErrorMessageHandler = null; if (!this.CanAddReference(out referenceErrorMessageHandler)) { if (referenceErrorMessageHandler != null) { referenceErrorMessageHandler.DynamicInvoke(new object[] { }); } return; } // Link the node to the project file. this.BindReferenceData(); // At this point force the item to be refreshed this.ItemNode.RefreshProperties(); referencesFolder.AddChild(this); return; }
/// <summary> /// Recursively search if this project reference guid is in cycle. /// </summary> private bool IsReferenceInCycle(Guid projectGuid) { // TODO: This has got to be wrong, it doesn't work w/ other project types. IVsHierarchy hierarchy = VsShellUtilities.GetHierarchy(this.ProjectMgr.Site, projectGuid); IReferenceContainerProvider provider = hierarchy.GetProject().GetCommonProject() as IReferenceContainerProvider; if (provider != null) { IReferenceContainer referenceContainer = provider.GetReferenceContainer(); Utilities.CheckNotNull(referenceContainer, "Could not found the References virtual node"); foreach (ReferenceNode refNode in referenceContainer.EnumReferences()) { ProjectReferenceNode projRefNode = refNode as ProjectReferenceNode; if (projRefNode != null) { if (projRefNode.ReferencedProjectGuid == this.ProjectMgr.ProjectIDGuid) { return(true); } if (this.IsReferenceInCycle(projRefNode.ReferencedProjectGuid)) { return(true); } } } } return(false); }
public object ExtenderNames() { EnvDTE.ObjectExtenders extenderService = (EnvDTE.ObjectExtenders) this.HierarchyNode.GetService(typeof(EnvDTE.ObjectExtenders)); Utilities.CheckNotNull(extenderService, "Could not get the ObjectExtenders object from the services exposed by this property object"); return(extenderService.GetExtenderNames(this.ExtenderCATID, this)); }
protected override void DoDefaultAction() { FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager; Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); manager.Open(false, false, WindowFrameShowAction.Show); }
/// <summary> /// Renames the file node for a case only change. /// </summary> /// <param name="newFileName">The new file name.</param> private void RenameCaseOnlyChange(string oldName, string newName) { //Update the include for this item. string relName = CommonUtils.GetRelativeFilePath(this.ProjectMgr.ProjectHome, newName); Debug.Assert(String.Equals(this.ItemNode.GetMetadata(ProjectFileConstants.Include), relName, StringComparison.OrdinalIgnoreCase), "Not just changing the filename case"); this.ItemNode.Rename(relName); this.ItemNode.RefreshProperties(); UpdateCaption(); ProjectMgr.ReDrawNode(this, UIHierarchyElement.Caption); this.RenameChildNodes(this); // Refresh the property browser. IVsUIShell shell = this.ProjectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0)); //Select the new node in the hierarchy ExpandItem(EXPANDFLAGS.EXPF_SelectItem); }
/// <summary> /// Returns the handle to an icon build from the image of index /// iconIndex in the image list. /// </summary> public IntPtr GetIconHandle(int iconIndex) { Utilities.CheckNotNull(imageList); // Make sure that the list of handles is initialized. if (null == iconHandles) { InitHandlesList(); } // Verify that the index is inside the expected range. if ((iconIndex < 0) || (iconIndex >= iconHandles.Count)) { throw new ArgumentOutOfRangeException("iconIndex"); } // Check if the icon is in the cache. if (IntPtr.Zero == iconHandles[iconIndex]) { Bitmap bitmap = imageList.Images[iconIndex] as Bitmap; // If the image is not a bitmap, then we can not build the icon, // so we have to return a null handle. if (null == bitmap) { return(IntPtr.Zero); } iconHandles[iconIndex] = bitmap.GetHicon(); } return(iconHandles[iconIndex]); }
/// <summary> /// Maps back to the hierarchy or project item object corresponding to the browse object. /// </summary> /// <param name="hier">Reference to the hierarchy object.</param> /// <param name="itemid">Reference to the project item.</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public virtual int GetProjectItem(out IVsHierarchy hier, out uint itemid) { Utilities.CheckNotNull(node); hier = node.ProjectMgr.GetOuterInterface <IVsHierarchy>(); itemid = this.node.ID; return(VSConstants.S_OK); }
protected ProjectDocumentsListener(System.IServiceProvider serviceProviderParameter) { Utilities.ArgumentNotNull("serviceProviderParameter", serviceProviderParameter); this.serviceProvider = serviceProviderParameter; this.projectDocTracker = this.serviceProvider.GetService(typeof(SVsTrackProjectDocuments)) as IVsTrackProjectDocuments2; Utilities.CheckNotNull(this.projectDocTracker, "Could not get the IVsTrackProjectDocuments2 object from the services exposed by this project"); }
/// <summary> /// Gets the IVsTrackProjectDocuments2 object by asking the service provider for it. /// </summary> /// <returns>the IVsTrackProjectDocuments2 object</returns> private IVsTrackProjectDocuments2 GetIVsTrackProjectDocuments2() { Debug.Assert(this.projectMgr != null && !this.projectMgr.IsClosed && this.projectMgr.Site != null); var documentTracker = this.projectMgr.Site.GetService(typeof(SVsTrackProjectDocuments)) as IVsTrackProjectDocuments2; Utilities.CheckNotNull(documentTracker); return(documentTracker); }
/// <summary> /// Open a file depending on the SubType property associated with the file item in the project file /// </summary> protected override void DoDefaultAction() { var manager = this.GetDocumentManager() as FileDocumentManager; Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); var viewGuid = (this.IsFormSubType ? VSConstants.LOGVIEWID_Designer : VSConstants.LOGVIEWID_Code); manager.Open(false, false, viewGuid, out var frame, WindowFrameShowAction.Show); }
/// <summary> /// Open a file depending on the SubType property associated with the file item in the project file /// </summary> protected override void DoDefaultAction() { var manager = this.GetDocumentManager() as FileDocumentManager; Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); if (manager == null) { var viewGuid = Guid.Empty; IVsWindowFrame frame; manager.Open(false, false, viewGuid, out frame, WindowFrameShowAction.Show); } }
protected override object PreCreateForOuter(IntPtr outerProjectIUnknown) { Utilities.CheckNotNull(this.buildProject, "The build project should have been initialized before calling PreCreateForOuter."); // Please be very carefull what is initialized here on the ProjectNode. Normally this should only instantiate and return a project node. // The reason why one should very carefully add state to the project node here is that at this point the aggregation has not yet been created and anything that would cause a CCW for the project to be created would cause the aggregation to fail // Our reasoning is that there is no other place where state on the project node can be set that is known by the Factory and has to execute before the Load method. ProjectNode node = this.CreateProject(); Utilities.CheckNotNull(node, "The project failed to be created"); node.BuildEngine = this.buildEngine; node.BuildProject = this.buildProject; return(node); }
/// <summary> /// Open a file depending on the SubType property associated with the file item in the project file /// </summary> protected override void DoDefaultAction() { if ("WebBrowser".Equals(this.SubType, StringComparison.OrdinalIgnoreCase)) { CommonPackage.OpenVsWebBrowser(this.ProjectMgr.Site, this.Url); return; } var manager = this.GetDocumentManager() as FileDocumentManager; Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); var viewGuid = Guid.Empty; manager.Open(false, false, viewGuid, out var frame, WindowFrameShowAction.Show); }
/// <summary> /// Open a file depending on the SubType property associated with the file item in the project file /// </summary> protected override void DoDefaultAction() { FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager; Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); IVsWindowFrame frame; if (IsFormSubType) { manager.Open(false, false, VSConstants.LOGVIEWID_Designer, out frame, WindowFrameShowAction.Show); } else { //manager.Open(false, false, VSConstants.LOGVIEWID_Code, out frame, WindowFrameShowAction.Show); // Do not use, as in VS2010 css files are opened as plain text manager.Open(false, false, WindowFrameShowAction.Show); } }
/// <summary> /// Get reference to IVsUIHierarchyWindow interface from guid persistence slot. /// </summary> /// <param name="serviceProvider">The service provider.</param> /// <param name="persistenceSlot">Unique identifier for a tool window created using IVsUIShell::CreateToolWindow. /// The caller of this method can use predefined identifiers that map to tool windows if those tool windows /// are known to the caller. </param> /// <returns>A reference to an IVsUIHierarchyWindow interface.</returns> public static IVsUIHierarchyWindow GetUIHierarchyWindow(IServiceProvider serviceProvider, Guid persistenceSlot) { Utilities.ArgumentNotNull("serviceProvider", serviceProvider); IVsUIShell shell = serviceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); object pvar; IVsWindowFrame frame; if (ErrorHandler.Succeeded(shell.FindToolWindow(0, ref persistenceSlot, out frame)) && ErrorHandler.Succeeded(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out pvar))) { return(pvar as IVsUIHierarchyWindow); } return(null); }
/// <summary> /// Checks if a reference is already added. The method parses all references and compares the Url. /// </summary> /// <returns>true if the assembly has already been added.</returns> protected virtual bool IsAlreadyAdded() { var referencesFolder = this.ProjectMgr.GetReferenceContainer() as ReferenceContainerNode; Utilities.CheckNotNull(referencesFolder, "Could not find the References node"); for (var n = referencesFolder.FirstChild; n != null; n = n.NextSibling) { if (n is ReferenceNode refererenceNode) { // We check if the Url of the assemblies is the same. if (CommonUtils.IsSamePath(refererenceNode.Url, this.Url)) { return(true); } } } return(false); }
/// <summary> /// Rename Folder /// </summary> /// <param name="label">new Name of Folder</param> /// <returns>VSConstants.S_OK, if succeeded</returns> public override int SetEditLabel(string label) { if (IsBeingCreated) { return(FinishFolderAdd(label, false)); } else { if (String.Equals(Path.GetFileName(CommonUtils.TrimEndSeparator(this.Url)), label, StringComparison.Ordinal)) { // Label matches current Name return(VSConstants.S_OK); } string newPath = CommonUtils.NormalizeDirectoryPath(Path.Combine( Path.GetDirectoryName(CommonUtils.TrimEndSeparator(this.Url)), label)); // Verify that No Directory/file already exists with the new name among current children var existingChild = Parent.FindImmediateChildByName(label); if (existingChild != null && existingChild != this) { return(ShowFileOrFolderAlreadyExistsErrorMessage(newPath)); } // Verify that No Directory/file already exists with the new name on disk if (Directory.Exists(newPath) || File.Exists(newPath)) { return(ShowFileOrFolderAlreadyExistsErrorMessage(newPath)); } if (!ProjectMgr.Tracker.CanRenameItem(Url, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_Directory)) { return(VSConstants.S_OK); } } try { var oldTriggerFlag = this.ProjectMgr.EventTriggeringFlag; ProjectMgr.EventTriggeringFlag |= ProjectNode.EventTriggering.DoNotTriggerTrackerQueryEvents; try { RenameFolder(label); } finally { ProjectMgr.EventTriggeringFlag = oldTriggerFlag; } //Refresh the properties in the properties window IVsUIShell shell = this.ProjectMgr.GetService(typeof(SVsUIShell)) as IVsUIShell; Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0)); // Notify the listeners that the name of this folder is changed. This will // also force a refresh of the SolutionExplorer's node. ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0); } catch (Exception e) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.RenameFolder, CultureInfo.CurrentUICulture), e.Message)); } return(VSConstants.S_OK); }
/// <summary> /// Performs a SaveAs operation of an open document. Called from SaveItem after the running document table has been updated with the new doc data. /// </summary> /// <param name="docData">A pointer to the document in the rdt</param> /// <param name="newFilePath">The new file path to the document</param> /// <returns></returns> internal override int AfterSaveItemAs(IntPtr docData, string newFilePath) { Utilities.ArgumentNotNullOrEmpty("newFilePath", newFilePath); int returnCode = VSConstants.S_OK; newFilePath = newFilePath.Trim(); //Identify if Path or FileName are the same for old and new file string newDirectoryName = CommonUtils.NormalizeDirectoryPath(Path.GetDirectoryName(newFilePath)); string oldDirectoryName = CommonUtils.NormalizeDirectoryPath(Path.GetDirectoryName(this.GetMkDocument())); bool isSamePath = CommonUtils.IsSameDirectory(newDirectoryName, oldDirectoryName); bool isSameFile = CommonUtils.IsSamePath(newFilePath, this.Url); //Get target container HierarchyNode targetContainer = null; bool isLink = false; if (isSamePath) { targetContainer = this.Parent; } else if (!CommonUtils.IsSubpathOf(this.ProjectMgr.ProjectHome, newDirectoryName)) { targetContainer = this.Parent; isLink = true; } else if (CommonUtils.IsSameDirectory(this.ProjectMgr.ProjectHome, newDirectoryName)) { //the projectnode is the target container targetContainer = this.ProjectMgr; } else { //search for the target container among existing child nodes targetContainer = this.ProjectMgr.FindNodeByFullPath(newDirectoryName); if (targetContainer != null && (targetContainer is FileNode)) { // We already have a file node with this name in the hierarchy. throw new InvalidOperationException(SR.GetString(SR.FileAlreadyExistsAndCannotBeRenamed, Path.GetFileName(newFilePath))); } } if (targetContainer == null) { // Add a chain of subdirectories to the project. string relativeUri = CommonUtils.GetRelativeDirectoryPath(this.ProjectMgr.ProjectHome, newDirectoryName); targetContainer = this.ProjectMgr.CreateFolderNodes(relativeUri); } Utilities.CheckNotNull(targetContainer, "Could not find a target container"); //Suspend file changes while we rename the document string oldrelPath = this.ItemNode.GetMetadata(ProjectFileConstants.Include); string oldName = CommonUtils.GetAbsoluteFilePath(this.ProjectMgr.ProjectHome, oldrelPath); SuspendFileChanges sfc = new SuspendFileChanges(this.ProjectMgr.Site, oldName); sfc.Suspend(); try { // Rename the node. DocumentManager.UpdateCaption(this.ProjectMgr.Site, Path.GetFileName(newFilePath), docData); // Check if the file name was actually changed. // In same cases (e.g. if the item is a file and the user has changed its encoding) this function // is called even if there is no real rename. if (!isSameFile || (this.Parent.ID != targetContainer.ID)) { // The path of the file is changed or its parent is changed; in both cases we have // to rename the item. if (isLink != IsLinkFile) { if (isLink) { var newPath = CommonUtils.GetRelativeFilePath( this.ProjectMgr.ProjectHome, Path.Combine(Path.GetDirectoryName(Url), Path.GetFileName(newFilePath)) ); ItemNode.SetMetadata(ProjectFileConstants.Link, newPath); } else { ItemNode.SetMetadata(ProjectFileConstants.Link, null); } SetIsLinkFile(isLink); } RenameFileNode(oldName, newFilePath, targetContainer); ProjectMgr.OnInvalidateItems(this.Parent); } } catch (Exception e) { Trace.WriteLine("Exception : " + e.Message); this.RecoverFromRenameFailure(newFilePath, oldrelPath); throw; } finally { sfc.Resume(); } return(returnCode); }
/// <summary> /// Renames a file node. /// </summary> /// <param name="label">The new name.</param> /// <returns>An errorcode for failure or S_OK.</returns> /// <exception cref="InvalidOperationException" if the file cannot be validated> /// <devremark> /// We are going to throw instead of showing messageboxes, since this method is called from various places where a dialog box does not make sense. /// For example the FileNodeProperties are also calling this method. That should not show directly a messagebox. /// Also the automation methods are also calling SetEditLabel /// </devremark> public override int SetEditLabel(string label) { // IMPORTANT NOTE: This code will be called when a parent folder is renamed. As such, it is // expected that we can be called with a label which is the same as the current // label and this should not be considered a NO-OP. if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { return(VSConstants.E_FAIL); } // Validate the filename. if (String.IsNullOrEmpty(label)) { throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, label)); } else if (label.Length > NativeMethods.MAX_PATH) { throw new InvalidOperationException(SR.GetString(SR.PathTooLong, label)); } else if (Utilities.IsFileNameInvalid(label)) { throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, label)); } for (HierarchyNode n = this.Parent.FirstChild; n != null; n = n.NextSibling) { // TODO: Distinguish between real Urls and fake ones (eg. "References") if (n != this && String.Equals(n.Caption, label, StringComparison.OrdinalIgnoreCase)) { //A file or folder with the name '{0}' already exists on disk at this location. Please choose another name. //If this file or folder does not appear in the Solution Explorer, then it is not currently part of your project. To view files which exist on disk, but are not in the project, select Show All Files from the Project menu. throw new InvalidOperationException(SR.GetString(SR.FileOrFolderAlreadyExists, label)); } } string fileName = Path.GetFileNameWithoutExtension(label); // Verify that the file extension is unchanged string strRelPath = Path.GetFileName(this.ItemNode.GetMetadata(ProjectFileConstants.Include)); if (!Utilities.IsInAutomationFunction(this.ProjectMgr.Site) && !String.Equals(Path.GetExtension(strRelPath), Path.GetExtension(label), StringComparison.OrdinalIgnoreCase)) { // Prompt to confirm that they really want to change the extension of the file string message = SR.GetString(SR.ConfirmExtensionChange, label); IVsUIShell shell = this.ProjectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); if (!VsShellUtilities.PromptYesNo(message, null, OLEMSGICON.OLEMSGICON_INFO, shell)) { // The user cancelled the confirmation for changing the extension. // Return S_OK in order not to show any extra dialog box return(VSConstants.S_OK); } } // Build the relative path by looking at folder names above us as one scenarios // where we get called is when a folder above us gets renamed (in which case our path is invalid) HierarchyNode parent = this.Parent; while (parent != null && (parent is FolderNode)) { strRelPath = Path.Combine(parent.Caption, strRelPath); parent = parent.Parent; } return(SetEditLabel(label, strRelPath)); }
/// <summary> /// Rename Folder /// </summary> /// <param name="label">new Name of Folder</param> /// <returns>VSConstants.S_OK, if succeeded</returns> public override int SetEditLabel(string label) { if (this.IsBeingCreated) { return(FinishFolderAdd(label, false)); } else { if (StringComparer.Ordinal.Equals(CommonUtils.GetFileOrDirectoryName(this.Url), label)) { // Label matches current Name return(VSConstants.S_OK); } var newPath = CommonUtils.GetAbsoluteDirectoryPath(CommonUtils.GetParent(this.Url), label); // Verify that No Directory/file already exists with the new name among current children var existingChild = this.Parent.FindImmediateChildByName(label); if (existingChild != null && existingChild != this) { return(ShowFileOrFolderAlreadyExistsErrorMessage(newPath)); } // Verify that No Directory/file already exists with the new name on disk. // Unless the path exists because it is the path to the source file also. if ((Directory.Exists(newPath) || File.Exists(newPath)) && !CommonUtils.IsSamePath(this.Url, newPath)) { return(ShowFileOrFolderAlreadyExistsErrorMessage(newPath)); } if (!this.ProjectMgr.Tracker.CanRenameItem(this.Url, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_Directory)) { return(VSConstants.S_OK); } } try { var oldTriggerFlag = this.ProjectMgr.EventTriggeringFlag; this.ProjectMgr.EventTriggeringFlag |= ProjectNode.EventTriggering.DoNotTriggerTrackerQueryEvents; try { RenameFolder(label); } finally { this.ProjectMgr.EventTriggeringFlag = oldTriggerFlag; } //Refresh the properties in the properties window var shell = this.ProjectMgr.GetService(typeof(SVsUIShell)) as IVsUIShell; Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0)); // Notify the listeners that the name of this folder is changed. This will // also force a refresh of the SolutionExplorer's node. this.ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0); } catch (Exception e) { if (e.IsCriticalException()) { throw; } throw new InvalidOperationException(SR.GetString(SR.RenameFolder, e.Message)); } return(VSConstants.S_OK); }