internal int AddItemWithSpecificInternal()

in Nodejs/Product/Nodejs/SharedProject/ProjectNode.cs [4342:4743]


        internal int AddItemWithSpecificInternal(uint itemIdLoc, VSADDITEMOPERATION op, string itemName, uint filesToOpen, string[] files, IntPtr dlgOwner, uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, VSADDRESULT[] result, bool? promptOverwrite = null)
        {
            if (files == null || result == null || files.Length == 0 || result.Length == 0)
            {
                return VSConstants.E_INVALIDARG;
            }

            // Locate the node to be the container node for the file(s) being added
            // only projectnode or foldernode and file nodes are valid container nodes
            // We need to locate the parent since the item wizard expects the parent to be passed.
            var n = this.NodeFromItemId(itemIdLoc);
            if (n == null)
            {
                return VSConstants.E_INVALIDARG;
            }

            while (!n.CanAddFiles && (!this.CanFileNodesHaveChilds || !(n is FileNode)))
            {
                n = n.Parent;
            }
            Debug.Assert(n != null, "We should at this point have either a ProjectNode or FolderNode or a FileNode as a container for the new filenodes");

            // handle link and runwizard operations at this point
            var isLink = false;
            switch (op)
            {
                case VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE:
                    // we do not support this right now
                    isLink = true;
                    break;

                case VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD:
                    result[0] = this.RunWizard(n, itemName, files[0], dlgOwner);
                    return VSConstants.S_OK;
            }

            var actualFiles = new string[files.Length];

            var flags = this.GetQueryAddFileFlags(files);

            var baseDir = this.GetBaseDirectoryForAddingFiles(n);
            // If we did not get a directory for node that is the parent of the item then fail.
            if (string.IsNullOrEmpty(baseDir))
            {
                return VSConstants.E_FAIL;
            }

            // Pre-calculates some paths that we can use when calling CanAddItems
            var filesToAdd = new List<string>();
            foreach (var file in files)
            {
                string fileName;
                var newFileName = string.Empty;

                switch (op)
                {
                    case VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE:
                        fileName = Path.GetFileName(itemName ?? file);
                        newFileName = CommonUtils.GetAbsoluteFilePath(baseDir, fileName);
                        break;
                    case VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE:
                    case VSADDITEMOPERATION.VSADDITEMOP_OPENFILE:
                        fileName = Path.GetFileName(file);
                        newFileName = CommonUtils.GetAbsoluteFilePath(baseDir, fileName);

                        if (isLink && CommonUtils.IsSubpathOf(this.ProjectHome, file))
                        {
                            // creating a link to a file that's actually in the project, it's not really a link.
                            isLink = false;

                            // If the file is not going to be added in its
                            // current path (GetDirectoryName(file) != baseDir),
                            // we need to update the filename and also update
                            // the destination node (n). Otherwise, we don't
                            // want to change the destination node (previous
                            // behavior) - just trust that our caller knows
                            // what they are doing. (Web Essentials relies on
                            // this.)
                            if (!CommonUtils.IsSameDirectory(baseDir, Path.GetDirectoryName(file)))
                            {
                                newFileName = file;
                                n = this.CreateFolderNodes(Path.GetDirectoryName(file));
                            }
                        }
                        break;
                }
                filesToAdd.Add(newFileName);
            }

            // Ask tracker objects if we can add files
            if (!this.tracker.CanAddItems(filesToAdd.ToArray(), flags))
            {
                // We were not allowed to add the files
                return VSConstants.E_FAIL;
            }

            if (!this.QueryEditProjectFile(false))
            {
                throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
            }

            // Add the files to the hierarchy
            var actualFilesAddedIndex = 0;
            var itemsToInvalidate = new List<HierarchyNode>();
            for (var index = 0; index < filesToAdd.Count; index++)
            {
                HierarchyNode child;
                var overwrite = false;
                MsBuildProjectElement linkedFile = null;
                var newFileName = filesToAdd[index];

                var file = files[index];
                result[0] = VSADDRESULT.ADDRESULT_Failure;

                child = this.FindNodeByFullPath(newFileName);
                if (child != null)
                {
                    // If the file to be added is an existing file part of the hierarchy then continue.
                    if (CommonUtils.IsSamePath(file, newFileName))
                    {
                        if (child.IsNonMemberItem)
                        {
                            for (var node = child; node != null; node = node.Parent)
                            {
                                itemsToInvalidate.Add(node);
                                // We want to include the first member item, so
                                // this test is not part of the loop condition.
                                if (!node.IsNonMemberItem)
                                {
                                    break;
                                }
                            }
                            // https://pytools.codeplex.com/workitem/1251
                            ErrorHandler.ThrowOnFailure(child.IncludeInProject(false));
                        }
                        result[0] = VSADDRESULT.ADDRESULT_Cancel;
                        continue;
                    }
                    else if (isLink)
                    {
                        var message = "There is already a file of the same name in this folder.";
                        var title = string.Empty;
                        var icon = OLEMSGICON.OLEMSGICON_QUERY;
                        var buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                        var defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;

                        VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);

                        result[0] = VSADDRESULT.ADDRESULT_Cancel;
                        return (int)OleConstants.OLECMDERR_E_CANCELED;
                    }
                    else
                    {
                        var canOverWriteExistingItem = CanOverwriteExistingItem(file, newFileName, !child.IsNonMemberItem);
                        if (canOverWriteExistingItem == E_CANCEL_FILE_ADD)
                        {
                            result[0] = VSADDRESULT.ADDRESULT_Cancel;
                            return (int)OleConstants.OLECMDERR_E_CANCELED;
                        }
                        else if (canOverWriteExistingItem == (int)OleConstants.OLECMDERR_E_CANCELED)
                        {
                            result[0] = VSADDRESULT.ADDRESULT_Cancel;
                            return canOverWriteExistingItem;
                        }
                        else if (canOverWriteExistingItem == VSConstants.S_OK)
                        {
                            overwrite = true;
                        }
                        else
                        {
                            return canOverWriteExistingItem;
                        }
                    }
                }
                else
                {
                    if (isLink)
                    {
                        child = this.FindNodeByFullPath(file);
                        if (child != null)
                        {
                            var message = string.Format("There is already a link to '{0}'. A project cannot have more than one link to the same file.", file);
                            var title = string.Empty;
                            var icon = OLEMSGICON.OLEMSGICON_QUERY;
                            var buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                            var defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;

                            VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);

                            result[0] = VSADDRESULT.ADDRESULT_Cancel;
                            return (int)OleConstants.OLECMDERR_E_CANCELED;
                        }
                    }

                    if (newFileName.Length >= NativeMethods.MAX_PATH)
                    {
                        var icon = OLEMSGICON.OLEMSGICON_CRITICAL;
                        var buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                        var defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;

                        VsShellUtilities.ShowMessageBox(this.Site, FolderNode.PathTooLongMessage, null, icon, buttons, defaultButton);

                        result[0] = VSADDRESULT.ADDRESULT_Cancel;
                        return (int)OleConstants.OLECMDERR_E_CANCELED;
                    }

                    // we need to figure out where this file would be added and make sure there's
                    // not an existing link node at the same location
                    var filename = Path.GetFileName(newFileName);
                    var folder = this.FindNodeByFullPath(Path.GetDirectoryName(newFileName));
                    if (folder != null)
                    {
                        if (folder.FindImmediateChildByName(filename) != null)
                        {
                            var message = "There is already a file of the same name in this folder.";
                            var title = string.Empty;
                            var icon = OLEMSGICON.OLEMSGICON_QUERY;
                            var buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                            var defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;

                            VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);

                            result[0] = VSADDRESULT.ADDRESULT_Cancel;
                            return (int)OleConstants.OLECMDERR_E_CANCELED;
                        }
                    }
                }

                // If the file to be added is not in the same path copy it.
                if (!CommonUtils.IsSamePath(file, newFileName) || Directory.Exists(newFileName))
                {
                    if (!overwrite && File.Exists(newFileName))
                    {
                        var existingChild = this.FindNodeByFullPath(file);
                        if (existingChild == null || !existingChild.IsLinkFile)
                        {
                            var message = SR.GetString(SR.FileAlreadyExists, newFileName);
                            var title = string.Empty;
                            var icon = OLEMSGICON.OLEMSGICON_QUERY;
                            var buttons = OLEMSGBUTTON.OLEMSGBUTTON_YESNO;
                            var defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
                            if (isLink)
                            {
                                message = "There is already a file of the same name in this folder.";
                                buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
                            }

                            var messageboxResult = VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
                            if (messageboxResult != NativeMethods.IDYES)
                            {
                                result[0] = VSADDRESULT.ADDRESULT_Cancel;
                                return (int)OleConstants.OLECMDERR_E_CANCELED;
                            }
                        }
                    }

                    var updatingNode = this.FindNodeByFullPath(file);
                    if (updatingNode != null && updatingNode.IsLinkFile)
                    {
                        // we just need to update the link to the new path.
                        linkedFile = updatingNode.ItemNode as MsBuildProjectElement;
                    }
                    else if (Directory.Exists(file))
                    {
                        // http://pytools.codeplex.com/workitem/546

                        var hr = AddDirectory(result, n, file, promptOverwrite);
                        if (ErrorHandler.Failed(hr))
                        {
                            return hr;
                        }
                        result[0] = VSADDRESULT.ADDRESULT_Success;
                        continue;
                    }
                    else if (!isLink)
                    {
                        // Copy the file to the correct location.
                        // We will suppress the file change events to be triggered to this item, since we are going to copy over the existing file and thus we will trigger a file change event. 
                        // We do not want the filechange event to ocur in this case, similar that we do not want a file change event to occur when saving a file.
                        var fileChange = this.site.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx;
                        Utilities.CheckNotNull(fileChange);

                        try
                        {
                            ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(VSConstants.VSCOOKIE_NIL, newFileName, 1));
                            if (op == VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE)
                            {
                                this.AddFileFromTemplate(file, newFileName);
                            }
                            else
                            {
                                PackageUtilities.CopyUrlToLocal(new Uri(file), newFileName);

                                // Reset RO attribute on file if present - for example, if source file was under TFS control and not checked out.
                                try
                                {
                                    var fileInfo = new FileInfo(newFileName);
                                    if (fileInfo.Attributes.HasFlag(FileAttributes.ReadOnly))
                                    {
                                        fileInfo.Attributes &= ~FileAttributes.ReadOnly;
                                    }
                                }
                                catch (Exception ex) when (!ExceptionExtensions.IsCriticalException(ex))
                                {
                                    // Best-effort, but no big deal if this fails.
                                }
                            }
                        }
                        finally
                        {
                            ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(VSConstants.VSCOOKIE_NIL, newFileName, 0));
                        }
                    }
                }

                if (overwrite)
                {
                    if (child.IsNonMemberItem)
                    {
                        ErrorHandler.ThrowOnFailure(child.IncludeInProject(false));
                    }
                }
                else if (linkedFile != null || isLink)
                {
                    // files not moving, add the old name, and set the link.
                    var friendlyPath = CommonUtils.GetRelativeFilePath(this.ProjectHome, file);
                    FileNode newChild;
                    if (linkedFile == null)
                    {
                        Debug.Assert(!CommonUtils.IsSubpathOf(this.ProjectHome, file), "Should have cleared isLink above for file in project dir");
                        newChild = CreateFileNode(file);
                    }
                    else
                    {
                        newChild = CreateFileNode(linkedFile);
                    }

                    newChild.SetIsLinkFile(true);
                    newChild.ItemNode.SetMetadata(ProjectFileConstants.Link, CommonUtils.CreateFriendlyFilePath(this.ProjectHome, newFileName));
                    n.AddChild(newChild);

                    DocumentManager.RenameDocument(this.site, file, file, n.ID);

                    LinkFileAdded(file);
                }
                else
                {
                    //Add new filenode/dependentfilenode
                    this.AddNewFileNodeToHierarchy(n, newFileName);
                }

                result[0] = VSADDRESULT.ADDRESULT_Success;
                actualFiles[actualFilesAddedIndex++] = newFileName;
            }

            // Notify listeners that items were appended.
            if (actualFilesAddedIndex > 0)
            {
                OnItemsAppended(n);
            }

            foreach (var node in itemsToInvalidate.Where(node => node != null).Reverse())
            {
                OnInvalidateItems(node);
            }

            //Open files if this was requested through the editorFlags
            var openFiles = (editorFlags & (uint)__VSSPECIFICEDITORFLAGS.VSSPECIFICEDITOR_DoOpen) != 0;
            if (openFiles && actualFiles.Length <= filesToOpen)
            {
                for (var i = 0; i < filesToOpen; i++)
                {
                    if (!string.IsNullOrEmpty(actualFiles[i]))
                    {
                        var name = actualFiles[i];
                        var child = this.FindNodeByFullPath(name);
                        Debug.Assert(child != null, "We should have been able to find the new element in the hierarchy");
                        if (child != null)
                        {
                            IVsWindowFrame frame;
                            if (editorType == Guid.Empty)
                            {
                                var view = child.DefaultOpensWithDesignView ? VSConstants.LOGVIEWID.Designer_guid : Guid.Empty;
                                ErrorHandler.ThrowOnFailure(this.OpenItem(child.ID, ref view, IntPtr.Zero, out frame));
                            }
                            else
                            {
                                ErrorHandler.ThrowOnFailure(this.OpenItemWithSpecific(child.ID, editorFlags, ref editorType, physicalView, ref logicalView, IntPtr.Zero, out frame));
                            }

                            // Show the window frame in the UI and make it the active window
                            if (frame != null)
                            {
                                ErrorHandler.ThrowOnFailure(frame.Show());
                            }
                        }
                    }
                }
            }

            return VSConstants.S_OK;
        }