public override int OnAfterOpenProject(IVsHierarchy hierarchy, int added)
        {
            // If this is a new project and our project. We use here that it is only our project that will implemnet the "internal"  IBuildDependencyOnProjectContainer.
            if (added != 0 && hierarchy is IBuildDependencyUpdate)
            {
                IVsUIHierarchy uiHierarchy = hierarchy as IVsUIHierarchy;
                Debug.Assert(uiHierarchy != null, "The ProjectNode should implement IVsUIHierarchy");
                // Expand and select project node
                IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ServiceProvider, HierarchyNode.SolutionExplorer);
                if (uiWindow != null)
                {
                    __VSHIERARCHYITEMSTATE state;
                    uint stateAsInt;
                    if (uiWindow.GetItemState(uiHierarchy, VSConstants.VSITEMID_ROOT, (uint)__VSHIERARCHYITEMSTATE.HIS_Expanded, out stateAsInt) == VSConstants.S_OK)
                    {
                        state = (__VSHIERARCHYITEMSTATE)stateAsInt;
                        if (state != __VSHIERARCHYITEMSTATE.HIS_Expanded)
                        {
                            int hr;
                            hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_ExpandParentsToShowItem);
                            if (ErrorHandler.Failed(hr))
                            {
                                Trace.WriteLine("Failed to expand project node");
                            }
                            hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_SelectItem);
                            if (ErrorHandler.Failed(hr))
                            {
                                Trace.WriteLine("Failed to select project node");
                            }

                            return(hr);
                        }
                    }
                }
            }
            return(VSConstants.S_OK);
        }
Exemplo n.º 2
0
        /// <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);
                }
            }));
        }