public virtual int AddItemWithSpecific(uint itemIdLoc, VSADDITEMOPERATION op, string itemName, uint filesToOpen, string[] files, IntPtr dlgOwner, uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, VSADDRESULT[] result) { 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. HierarchyNode n = this.NodeFromItemId(itemIdLoc); if (n == null) { return VSConstants.E_INVALIDARG; } while ((!(n is ProjectNode)) && (!(n is FolderNode)) && (!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"); if (op == VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD) { result[0] = this.RunWizard(n, itemName, files[0], dlgOwner); return VSConstants.S_OK; } string[] actualFiles = new string[files.Length]; VSQUERYADDFILEFLAGS[] flags = this.GetQueryAddFileFlags(files); string 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 List<string> filesToAdd = new List<string>(); for (int index = 0; index < files.Length; index++) { string newFileName = String.Empty; string file = files[index]; switch (op) { case VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE: { string fileName = Path.GetFileName(itemName); newFileName = Path.Combine(baseDir, fileName); } break; case VSADDITEMOPERATION.VSADDITEMOP_OPENFILE: case VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE: { string fileName = Path.GetFileName(file); newFileName = Path.Combine(baseDir, fileName); } 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.ProjectManager.QueryEditProjectFile(false)) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } // Add the files to the hierarchy int actualFilesAddedIndex = 0; for (int index = 0; index < filesToAdd.Count; index++) { HierarchyNode child; bool overwrite = false; string newFileName = filesToAdd[index]; string file = files[index]; result[0] = VSADDRESULT.ADDRESULT_Failure; child = this.FindChild(newFileName); if (child != null) { // If the file to be added is an existing file part of the hierarchy then continue. if (NativeMethods.IsSamePath(file, newFileName)) { result[0] = VSADDRESULT.ADDRESULT_Cancel; continue; } int canOverWriteExistingItem = this.CanOverwriteExistingItem(file, newFileName); 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; } } // If the file to be added is not in the same path copy it. if (op != VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE && NativeMethods.IsSamePath(file, newFileName) == false) { if (!overwrite && File.Exists(newFileName)) { string message = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.FileAlreadyExists, CultureInfo.CurrentUICulture), newFileName); string title = string.Empty; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_QUERY; OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_YESNO; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; int messageboxResult = VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton); if (messageboxResult == DialogResult.No) { result[0] = VSADDRESULT.ADDRESULT_Cancel; return (int)OleConstants.OLECMDERR_E_CANCELED; } } // 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. IVsFileChangeEx fileChange = this._site.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx; if (fileChange == null) { throw new InvalidOperationException(); } 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); } } finally { ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(VSConstants.VSCOOKIE_NIL, newFileName, 0)); } } if (overwrite) { this.OverwriteExistingItem(child); } else if (op == VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE) { Url baseUrl = new Url(this.ProjectFolder + Path.DirectorySeparatorChar); string relativePath = baseUrl.MakeRelative(new Url(file)); string linkPath = baseUrl.MakeRelative(new Url(newFileName)); this.AddNewFileNodeToHierarchy(n, relativePath, linkPath); } else { //Add new filenode/dependentfilenode this.AddNewFileNodeToHierarchy(n, newFileName, null); } result[0] = VSADDRESULT.ADDRESULT_Success; actualFiles[actualFilesAddedIndex++] = newFileName; } // Notify listeners that items were appended. if (actualFilesAddedIndex > 0) n.OnItemsAppended(n); //Open files if this was requested through the editorFlags bool openFiles = (editorFlags & (uint)__VSSPECIFICEDITORFLAGS.VSSPECIFICEDITOR_DoOpen) != 0; if (openFiles && actualFiles.Length <= filesToOpen) { for (int i = 0; i < filesToOpen; i++) { if (!String.IsNullOrEmpty(actualFiles[i])) { string name = actualFiles[i]; HierarchyNode child = this.FindChild(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) { Guid view = 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; }
public static string GetRelativePath(string basePath, string subpath) { VerifyStringArgument(basePath, "basePath"); VerifyStringArgument(subpath, "subpath"); if (!Path.IsPathRooted(basePath)) { throw new ArgumentException("The 'basePath' is not rooted."); } if (!Path.IsPathRooted(subpath)) { return subpath; } if (!String.Equals(Path.GetPathRoot(basePath), Path.GetPathRoot(subpath), StringComparison.OrdinalIgnoreCase)) { // both paths have different roots so we can't make them relative return subpath; } // Url.MakeRelative method requires the base path to be ended with a '\' if it is a folder, // otherwise it considers it as a file so we need to make sure that the folder path is right basePath = EnsureTrailingDirectoryChar(basePath.Trim()); Url url = new Url(basePath); return url.MakeRelative(new Url(subpath)); }