예제 #1
0
파일: FileNode.cs 프로젝트: majocha/fsharp
        /// <summary>
        /// Get's called to rename the eventually running document this hierarchyitem points to
        /// </summary>
        /// returns FALSE if the doc can not be renamed
        public bool RenameDocument(string oldName, string newName)
        {
            IVsRunningDocumentTable pRDT = this.GetService(typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable;

            if (pRDT == null)
            {
                return(false);
            }
            IntPtr       docData = IntPtr.Zero;
            IVsHierarchy pIVsHierarchy;
            uint         itemId;
            uint         uiVsDocCookie;

            SuspendFileChanges sfc = new SuspendFileChanges(this.ProjectMgr.Site, oldName);

            sfc.Suspend();

            try
            {
                VSRENAMEFILEFLAGS renameflag = VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags;
                ErrorHandler.ThrowOnFailure(pRDT.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, oldName, out pIVsHierarchy, out itemId, out docData, out uiVsDocCookie));

                if (pIVsHierarchy != null && !Utilities.IsSameComObject(pIVsHierarchy, this.ProjectMgr))
                {
                    // Don't rename it if it wasn't opened by us.
                    return(false);
                }

                // ask other potentially running packages
                if (!this.ProjectMgr.Tracker.CanRenameItem(oldName, newName, renameflag))
                {
                    return(false);
                }
                // Allow the user to "fix" the project by renaming the item in the hierarchy
                // to the real name of the file on disk.
                bool shouldRenameInStorage = IsFileOnDisk(oldName) || !IsFileOnDisk(newName);
                Transactional.Try(
                    // Action
                    () => { if (shouldRenameInStorage)
                            {
                                RenameInStorage(oldName, newName);
                            }
                    },
                    // Compensation
                    () => { if (shouldRenameInStorage)
                            {
                                RenameInStorage(newName, oldName);
                            }
                    },
                    // Continuation
                    () =>
                {
                    string newFileName = Path.GetFileName(newName);
                    string oldCaption  = this.Caption;
                    Transactional.Try(
                        // Action
                        () => DocumentManager.UpdateCaption(this.ProjectMgr.Site, newFileName, docData),
                        // Compensation
                        () => DocumentManager.UpdateCaption(this.ProjectMgr.Site, oldCaption, docData),
                        // Continuation
                        () =>
                    {
                        bool caseOnlyChange = NativeMethods.IsSamePath(oldName, newName);
                        if (!caseOnlyChange)
                        {
                            // Check out the project file if necessary.
                            if (!this.ProjectMgr.QueryEditProjectFile(false))
                            {
                                throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
                            }
                            this.RenameFileNode(oldName, newName);
                        }
                        else
                        {
                            this.RenameCaseOnlyChange(newFileName);
                        }
                        bool extensionWasChanged = (0 != String.Compare(Path.GetExtension(oldName), Path.GetExtension(newName), StringComparison.OrdinalIgnoreCase));
                        if (extensionWasChanged)
                        {
                            // Update the BuildAction
                            this.ItemNode.ItemName = this.ProjectMgr.DefaultBuildAction(newName);
                        }
                        this.ProjectMgr.Tracker.OnItemRenamed(oldName, newName, renameflag);
                    });
                });
            }
            finally
            {
                if (docData != IntPtr.Zero)
                {
                    Marshal.Release(docData);
                }
                sfc.Resume(); // can throw, e.g. when RenameFileNode failed, but file was renamed on disk and now editor cannot find file
            }

            return(true);
        }
예제 #2
0
파일: FileNode.cs 프로젝트: majocha/fsharp
        /// <summary>
        /// Renames the file in the hierarchy by removing old node and adding a new node in the hierarchy.
        /// </summary>
        /// <param name="oldFileName">The old file name.</param>
        /// <param name="newFileName">The new file name</param>
        /// <param name="newParentId">The new parent id of the item.</param>
        /// <returns>The newly added FileNode.</returns>
        /// <remarks>While a new node will be used to represent the item, the underlying MSBuild item will be the same and as a result file properties saved in the project file will not be lost.</remarks>
        public virtual FileNode RenameFileNode(string oldFileName, string newFileName, uint newParentId)
        {
            if (string.Compare(oldFileName, newFileName, StringComparison.Ordinal) == 0)
            {
                // We do not want to rename the same file
                return(null);
            }

            string[] file = new string[1];
            file[0] = newFileName;
            VSADDRESULT[] result    = new VSADDRESULT[1];
            Guid          emptyGuid = Guid.Empty;

            FileNode childAdded      = null;
            string   originalInclude = this.ItemNode.Item.UnevaluatedInclude;

            return(Transactional.Try(
                       // Action
                       () =>
            {
                // It's unfortunate that MPF implements rename in terms of AddItemWithSpecific. Since this
                // is the case, we have to pass false to prevent AddITemWithSpecific to fire Add events on
                // the IVsTrackProjectDocuments2 tracker. Otherwise, clients listening to this event
                // (SCCI, for example) will be really confused.
                using (this.ProjectMgr.ExtensibilityEventsHelper.SuspendEvents())
                {
                    var currentId = this.ID;

                    // actual deletion is delayed until all checks are passed
                    Func <uint> getIdOfExistingItem =
                        () =>
                    {
                        this.OnItemDeleted();
                        this.Parent.RemoveChild(this);
                        return currentId;
                    };

                    // raises OnItemAdded inside
                    ErrorHandler.ThrowOnFailure(this.ProjectMgr.AddItemWithSpecific(newParentId, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, 0, file, IntPtr.Zero, 0, ref emptyGuid, null, ref emptyGuid, result, false, getIdOfExistingItem));
                    childAdded = this.ProjectMgr.FindChild(newFileName) as FileNode;
                    Debug.Assert(childAdded != null, "Could not find the renamed item in the hierarchy");
                }
            },
                       // Compensation
                       () =>
            {
                // it failed, but 'this' is dead and 'childAdded' is here to stay, so fix the latter back
                using (this.ProjectMgr.ExtensibilityEventsHelper.SuspendEvents())
                {
                    childAdded.ItemNode.Rename(originalInclude);
                    childAdded.ItemNode.RefreshProperties();
                }
            },

                       // Continuation
                       () =>
            {
                // Since this node has been removed all of its state is zombied at this point
                // Do not call virtual methods after this point since the object is in a deleted state.

                // Remove the item created by the add item. We need to do this otherwise we will have two items.
                // Please be aware that we have not removed the ItemNode associated to the removed file node from the hierrachy.
                // What we want to achieve here is to reuse the existing build item.
                // We want to link to the newly created node to the existing item node and addd the new include.

                //temporarily keep properties from new itemnode since we are going to overwrite it
                string newInclude = childAdded.ItemNode.Item.UnevaluatedInclude;
                string dependentOf = childAdded.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon);
                childAdded.ItemNode.RemoveFromProjectFile();

                // Assign existing msbuild item to the new childnode
                childAdded.ItemNode = this.ItemNode;
                childAdded.ItemNode.Item.ItemType = this.ItemNode.ItemName;
                childAdded.ItemNode.Item.Xml.Include = newInclude;
                if (!string.IsNullOrEmpty(dependentOf))
                {
                    childAdded.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, dependentOf);
                }
                childAdded.ItemNode.RefreshProperties();

                // Extensibilty events has rename
                this.ProjectMgr.ExtensibilityEventsHelper.FireItemRenamed(childAdded, Path.GetFileName(originalInclude));

                //Update the new document in the RDT.
                try
                {
                    DocumentManager.RenameDocument(this.ProjectMgr.Site, oldFileName, newFileName, childAdded.ID);

                    // The current automation node is renamed, but the hierarchy ID is now pointing to the old item, which
                    // is invalid. Update it.
                    this.ID = childAdded.ID;

                    //Update FirstChild
                    childAdded.FirstChild = this.FirstChild;

                    //Update ChildNodes
                    SetNewParentOnChildNodes(childAdded);
                    RenameChildNodes(childAdded);

                    return childAdded;
                }
                finally
                {
                    //Select the new node in the hierarchy
                    IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ProjectMgr.Site, SolutionExplorer);
                    uiWindow.ExpandItem(this.ProjectMgr.InteropSafeIVsUIHierarchy, childAdded.ID, EXPANDFLAGS.EXPF_SelectItem);
                }
            }));
        }