private Addition CanAddFileFromProjectReference()

in Common/Product/SharedProject/ProjectNode.CopyPaste.cs [907:1104]


            private Addition CanAddFileFromProjectReference(string projectRef, string targetFolder, bool fromFolder = false) {
                Utilities.ArgumentNotNullOrEmpty("projectRef", projectRef);

                IVsSolution solution = Project.GetService(typeof(IVsSolution)) as IVsSolution;
                Utilities.CheckNotNull(solution);

                uint itemidLoc;
                IVsHierarchy hierarchy;
                string str;
                VSUPDATEPROJREFREASON[] reason = new VSUPDATEPROJREFREASON[1];
                if (ErrorHandler.Failed(solution.GetItemOfProjref(projectRef, out hierarchy, out itemidLoc, out str, reason))) {
                    // the file may have been deleted between the copy & paste
                    string path;
                    Guid projectGuid;
                    GetPathAndProjectId(projectRef, out projectGuid, out path);
                    ReportMissingItem(path);
                    return null;
                }

                Utilities.CheckNotNull(hierarchy);

                // This will throw invalid cast exception if the hierrachy is not a project.
                IVsProject project = (IVsProject)hierarchy;
                object isLinkValue;
                bool isLink = false;
                if (ErrorHandler.Succeeded(((IVsHierarchy)project).GetProperty(itemidLoc, (int)__VSHPROPID2.VSHPROPID_IsLinkFile, out isLinkValue))) {
                    if (isLinkValue is bool) {
                        isLink = (bool)isLinkValue;
                    }
                }

                string moniker;
                ErrorHandler.ThrowOnFailure(project.GetMkDocument(itemidLoc, out moniker));

                if (DropEffect == DropEffect.Move && IsBadMove(targetFolder, moniker, true)) {
                    return null;
                }

                if (!File.Exists(moniker)) {
                    Utilities.ShowMessageBox(
                            Project.Site,
                            String.Format("The item '{0}' does not exist in the project directory. It may have been moved, renamed or deleted.", Path.GetFileName(moniker)),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                // Check that the source and destination paths aren't the same since we can't move an item to itself.
                // If they are in fact the same location, throw an error that copy/move will not work correctly.
                if (DropEffect == DropEffect.Move && !CommonUtils.IsSamePath(Path.GetDirectoryName(moniker), Path.GetDirectoryName(targetFolder))) {
                    try {
                        string sourceLinkTarget = NativeMethods.GetAbsolutePathToDirectory(Path.GetDirectoryName(moniker));
                        string destinationLinkTarget = null;

                        // if the directory doesn't exist, just skip this.  We will create it later.
                        if (Directory.Exists(targetFolder)) {
                            try {
                                destinationLinkTarget = NativeMethods.GetAbsolutePathToDirectory(targetFolder);
                            } catch (FileNotFoundException) {
                                // This can occur if the user had a symlink'd directory and deleted the backing directory.
                                Utilities.ShowMessageBox(
                                            Project.Site,
                                            String.Format(
                                                "Unable to find the destination folder."),
                                            null,
                                            OLEMSGICON.OLEMSGICON_CRITICAL,
                                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                                return null;
                            }
                        }

                        // If the paths are the same, we can't really move the file...
                        if (destinationLinkTarget != null && CommonUtils.IsSamePath(sourceLinkTarget, destinationLinkTarget)) {
                            CannotMoveSameLocation(moniker);
                            return null;
                        }
                    } catch (Exception e) {
                        if (e.IsCriticalException()) {
                            throw;
                        }
                        TaskDialog.ForException(Project.Site, e, String.Empty, Project.IssueTrackerUrl).ShowModal();
                        return null;
                    }
                }

                // Begin the move operation now that we are past pre-checks.
                var existingChild = Project.FindNodeByFullPath(moniker);
                if (isLink) {
                    // links we just want to update the link node for...
                    if (existingChild != null) {
                        if (Utilities.IsSameComObject(Project, project)) {
                            if (DropEffect != DropEffect.Move) {
                                Utilities.ShowMessageBox(
                                        Project.Site,
                                        String.Format("Cannot copy linked files within the same project. You cannot have more than one link to the same file in a project."),
                                        null,
                                        OLEMSGICON.OLEMSGICON_CRITICAL,
                                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                                return null;
                            }
                        } else {
                            Utilities.ShowMessageBox(
                                    Project.Site,
                                    String.Format("There is already a link to '{0}'. You cannot have more than one link to the same file in a project.", moniker),
                                    null,
                                    OLEMSGICON.OLEMSGICON_CRITICAL,
                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                            return null;
                        }
                    }

                    return new ReparentLinkedFileAddition(Project, targetFolder, moniker);
                }

                string newPath = Path.Combine(targetFolder, Path.GetFileName(moniker));
                if (File.Exists(newPath) &&  
                    CommonUtils.IsSamePath(
                        NativeMethods.GetAbsolutePathToDirectory(newPath), 
                        NativeMethods.GetAbsolutePathToDirectory(moniker))) {
                    newPath = GetCopyName(newPath);
                }

                bool ok = false;
                if (DropEffect == DropEffect.Move && Utilities.IsSameComObject(project, Project)) {
                    if (existingChild != null && existingChild.ItemNode != null && existingChild.ItemNode.IsExcluded) {
                        // https://nodejstools.codeplex.com/workitem/271
                        // The item is excluded, so we don't need to ask if we can rename it.
                        ok = true;
                    } else {
                        ok = Project.Tracker.CanRenameItem(moniker, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags);
                    }
                } else {
                    ok = Project.Tracker.CanAddItems(
                        new[] { newPath },
                        new VSQUERYADDFILEFLAGS[] { VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags });
                }

                if (ok) {
                    if (File.Exists(newPath)) {
                        if (DropEffect == DropEffect.Move &&
                            Utilities.IsSameComObject(project, Project) &&
                            Project.FindNodeByFullPath(newPath) != null) {
                            // if we're overwriting an item, we're moving it, make sure that's ok.
                            // OverwriteFileAddition will handle the remove from the hierarchy
                            if (!Project.Tracker.CanRemoveItems(new[] { newPath }, new[] { VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags })) {
                                return null;
                            }
                        }
                        bool? overwrite = OverwriteAllItems;

                        if (overwrite == null) {
                            OverwriteFileDialog dialog;
                            if (!PromptOverwriteFile(moniker, out dialog)) {
                                return null;
                            }

                            overwrite = dialog.ShouldOverwrite;

                            if (dialog.AllItems) {
                                OverwriteAllItems = overwrite;
                            }
                        }

                        if (overwrite.Value) {
                            return new OverwriteFileAddition(Project, targetFolder, DropEffect, moniker, Path.GetFileName(newPath), project);
                        } else {
                            return SkipOverwriteAddition.Instance;
                        }
                    } else if (Directory.Exists(newPath)) {
                        Utilities.ShowMessageBox(
                            Project.Site,
                            SR.GetString(SR.DirectoryExists, CommonUtils.GetFileOrDirectoryName(newPath)),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }

                    if (newPath.Length >= NativeMethods.MAX_PATH) {
                        Utilities.ShowMessageBox(
                            Project.Site,
                            SR.GetString(SR.PathTooLongShortMessage),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }
                    return new FileAddition(Project, targetFolder, DropEffect, moniker, Path.GetFileName(newPath), project);
                }
                return null;
            }