Beispiel #1
0
        /// <summary>
        /// Removes the node from the project.
        /// </summary>
        /// <remarks>By default, this does nothing.</remarks>
        public virtual void RemoveFromProject()
        {
            // Don't do anything if we can't remove the node.
            if (!this.CanRemoveFromProject)
            {
                return;
            }

            FolderNode parentFolder = this.Parent;

            // We'd better have a parent.
            if (parentFolder == null)
            {
                Tracer.Fail("Cannot remove the root node from the project.");
                return;
            }

            // Our parent better have children.
            if (parentFolder.Children == null)
            {
                Tracer.Fail("This node's ({0}) parent ({1}) should have a non-null Children collection.", this.ToString(), parentFolder.ToString());
                return;
            }

            // Before we remove ourself from the hierachy, make sure that we're not selected.
            // If we have to, we'll move the selection to the previous sibling.
            Node nodeToSelect = null;

            if (this.Selected)
            {
                // If the previous sibling is null, then select the root node.
                if (this.PreviousSibling != null)
                {
                    nodeToSelect = this.PreviousSibling;
                }
                else
                {
                    nodeToSelect = this.Hierarchy.RootNode;
                }
            }

            // Remove ourself from the parent.
            parentFolder.Children.Remove(this);

            // Now select the node. We have to do it here because the removal causes a refresh
            // on the hierarchy, which will select the root node by default.
            if (nodeToSelect != null)
            {
                nodeToSelect.Select();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Does the actual work of changing the caption after all of the verifications have been done
        /// that it's Ok to move the file.
        /// </summary>
        /// <param name="newCaption">The new caption.</param>
        /// <param name="newPath">The new absolute path.</param>
        public override void MoveNodeOnCaptionChange(string newCaption, string newPath)
        {
            string oldCaption            = this.Caption;
            string oldPath               = this.AbsolutePath;
            string oldRelativePath       = this.RelativePath;
            bool   updatedWindowCaptions = false;
            bool   removedNode           = false;
            Node   newNode               = null;

            // If we are currently selected, cache the value so we can restore the selection
            // after the addition.
            bool wasSelected = this.Selected;

            // Tell the environment to stop listening to file change events on the old file.
            using (FileChangeNotificationSuspender notificationSuspender = new FileChangeNotificationSuspender(oldPath))
            {
                // Make sure the environment says we can start the rename.
                if (!this.Hierarchy.AttachedProject.Tracker.CanRenameFile(oldPath, newPath))
                {
                    return;
                }

                // Move the file on the file system to match the new name.
                if (!this.IsVirtual && File.Exists(oldPath) && !File.Exists(newPath))
                {
                    Tracer.WriteLineInformation(classType, "MoveNodeOnCaptionChange", "Renaming the file '{0}' to '{1}'.", oldPath, newPath);
                    string newDirectoryName = Path.GetDirectoryName(newPath);
                    if (!Directory.Exists(newDirectoryName))
                    {
                        Directory.CreateDirectory(newDirectoryName);
                    }
                    File.Move(oldPath, newPath);
                }

                try
                {
                    // Update all of the windows that currently have this file opened in an editor.
                    this.UpdateOpenWindowCaptions(newCaption);
                    updatedWindowCaptions = true;

                    // We have to remove the node and re-add it so that we can have the sorting preserved.
                    // Also, if the extension has changed then we'll have to recreate a new type-specific
                    // FileNode. The easy way is to remove ourself from the project then tell the project
                    // to add an existing file.

                    string newRelativePath = PackageUtility.MakeRelative(this.Hierarchy.RootNode.AbsoluteDirectory, newPath);

                    // Remove ourself from the hierarchy.
                    this.Parent.Children.Remove(this);
                    removedNode = true;

                    // We have now been removed from the hierarchy. Do NOT call any virtual methods or
                    // methods that depend on our state after this point.

                    // Re-add ourself as a new incarnation (different object). Our life ends here.
                    newNode = this.Hierarchy.AddExistingFile(newRelativePath, true);

                    if (newNode != null)
                    {
                        // We need to set our hierarchy Id to match the new hierachy Id in case Visual Studio
                        // calls back into us for something.
                        this.SetHierarchyId(newNode.HierarchyId);

                        // Select the new node if we were previously selected.
                        if (wasSelected)
                        {
                            newNode.Select();
                        }

                        // Tell the RDT to rename the document.
                        Context.RunningDocumentTable.RenameDocument(oldPath, newPath, newNode.HierarchyId);
                    }
                }
                catch (Exception e)
                {
                    if (ErrorUtility.IsExceptionUnrecoverable(e))
                    {
                        throw;
                    }

                    // Rollback the file move
                    Tracer.WriteLineWarning(classType, "MoveNodeOnCaptionChange", "There was an error in renaming the document. Exception: {0}", e);
                    File.Move(newPath, oldPath);

                    // Remove the node that we just added.
                    if (newNode != null)
                    {
                        newNode.RemoveFromProject();
                    }

                    // Re-add a new node since we've already removed the old node.
                    if (removedNode || this.Parent == null)
                    {
                        newNode = this.Hierarchy.AddExistingFile(oldRelativePath, true);
                        this.SetHierarchyId(newNode.HierarchyId);
                        if (wasSelected)
                        {
                            newNode.Select();
                        }
                    }

                    // Rollback the caption update on open windows
                    if (updatedWindowCaptions)
                    {
                        this.UpdateOpenWindowCaptions(oldCaption);
                    }

                    // Rethrow the exception
                    throw;
                }

                // Tell the environment that we're done renaming the document.
                this.Hierarchy.AttachedProject.Tracker.OnFileRenamed(oldPath, newPath);

                // Update the property browser.
                IVsUIShell vsUIShell = (IVsUIShell)this.Hierarchy.ServiceProvider.GetServiceOrThrow(typeof(SVsUIShell), typeof(IVsUIShell), classType, "MoveNodeOnCaptionChange");
                vsUIShell.RefreshPropertyBrowser(0);
            }
        }