/// <summary> /// This is overridden to handle drop operations correctly in a help file builder project /// </summary> /// <inheritdoc /> public override int Drop(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { DropDataType dropDataType = DropDataType.None; if (pDataObject == null) { return(VSConstants.E_INVALIDARG); } pdwEffect = (uint)DropEffect.None; // If the source is within the project, let the base class handle it if (this.SourceDraggedOrCutOrCopied) { return(base.Drop(pDataObject, grfKeyState, itemid, ref pdwEffect)); } // Get the node that is being dragged over and ask it which node should handle this call HierarchyNode targetNode = NodeFromItemId(itemid); if (targetNode == null) { return(VSConstants.S_FALSE); } targetNode = targetNode.GetDragTargetHandlerNode(); dropDataType = this.HandleSelectionDataObject(pDataObject, targetNode); // Since we can get a mix of files that may not necessarily be moved into the project (i.e. // documentation sources and references), we'll always act as if they were copied. pdwEffect = (uint)DropEffect.Copy; return((dropDataType != DropDataType.Shell) ? VSConstants.E_FAIL : VSConstants.S_OK); }
/// <summary> /// Handle the Paste operation to a targetNode /// </summary> protected internal override int PasteFromClipboard(HierarchyNode targetNode) { int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; //Get the clipboardhelper service and use it after processing dataobject IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper)); if (clipboardHelper == null) { return(VSConstants.E_FAIL); } try { //Get dataobject from clipboard IOleDataObject dataObject = null; ErrorHandler.ThrowOnFailure(UnsafeNativeMethods.OleGetClipboard(out dataObject)); if (dataObject == null) { return(VSConstants.E_UNEXPECTED); } DropEffect dropEffect = DropEffect.None; DropDataType dropDataType = DropDataType.None; try { dropDataType = this.ProcessSelectionDataObject(dataObject, targetNode.GetDragTargetHandlerNode()); dropEffect = this.QueryDropEffect(dropDataType, 0); } catch (ExternalException e) { Trace.WriteLine("Exception : " + e.Message); // If it is a drop from windows and we get any kind of error ignore it. This // prevents bogus messages from the shell from being displayed if (dropDataType != DropDataType.Shell) { throw e; } } finally { // Inform VS (UiHierarchyWindow) of the paste returnValue = clipboardHelper.Paste(dataObject, (uint)dropEffect); } } catch (COMException e) { Trace.WriteLine("Exception : " + e.Message); returnValue = e.ErrorCode; } return(returnValue); }
/// <summary> /// Called when one or more items are dropped into the target hierarchy or hierarchy window when the mouse button is released. /// </summary> /// <param name="pDataObject">Reference to the IDataObject interface on the item being dragged. This data object contains the data being transferred in the drag-and-drop operation. /// If the drop occurs, then this data object (item) is incorporated into the target hierarchy or hierarchy window.</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See <seealso cref="IVsHierarchyDropDataTarget"/></param> /// <param name="itemid">Item identifier of the drop data target over which the item is being dragged</param> /// <param name="pdwEffect">Visual effects associated with the drag-and drop-operation, such as a cursor, bitmap, and so on. /// The value of dwEffects passed to the source object via the OnDropNotify method is the value of pdwEffects returned by the Drop method</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public override int Drop(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { if (pDataObject == null) { return(VSConstants.E_INVALIDARG); } pdwEffect = (uint)DropEffect.None; // Get the node that is being dragged over and ask it which node should handle this call HierarchyNode targetNode = NodeFromItemId(itemid); if (targetNode != null) { targetNode = targetNode.GetDragTargetHandlerNode(); } else { // There is no target node. The drop can not be completed. return(VSConstants.S_FALSE); } int returnValue; try { DropDataType dropDataType = DropDataType.None; dropDataType = ProcessSelectionDataObject(pDataObject, targetNode); pdwEffect = (uint)this.QueryDropEffect(dropDataType, grfKeyState); // If it is a drop from windows and we get any kind of error we return S_FALSE and dropeffect none. This // prevents bogus messages from the shell from being displayed returnValue = (dropDataType != DropDataType.Shell) ? VSConstants.E_FAIL : VSConstants.S_OK; } catch (System.IO.FileNotFoundException e) { Trace.WriteLine("Exception : " + e.Message); if (!Utilities.IsInAutomationFunction(this.Site)) { string message = e.Message; string title = string.Empty; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton); } returnValue = VSConstants.E_FAIL; } return(returnValue); }
/// <summary> /// Handle the Paste operation to a targetNode /// </summary> public override int PasteFromClipboard(HierarchyNode targetNode) { int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; //Get the clipboardhelper service and use it after processing dataobject IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper)); if (clipboardHelper == null) { return VSConstants.E_FAIL; } try { //Get dataobject from clipboard IOleDataObject dataObject = null; ErrorHandler.ThrowOnFailure(UnsafeNativeMethods.OleGetClipboard(out dataObject)); if (dataObject == null) { return VSConstants.E_UNEXPECTED; } DropEffect dropEffect = DropEffect.None; DropDataType dropDataType = DropDataType.None; try { dropDataType = this.ProcessSelectionDataObject(dataObject, targetNode.GetDragTargetHandlerNode()); dropEffect = this.QueryDropEffect(dropDataType, 0); } catch (ExternalException e) { Trace.WriteLine("Exception : " + e.Message); // If it is a drop from windows and we get any kind of error ignore it. This // prevents bogus messages from the shell from being displayed if (dropDataType != DropDataType.Shell) { throw; } } finally { // Inform VS (UiHierarchyWindow) of the paste returnValue = clipboardHelper.Paste(dataObject, (uint)dropEffect); } } catch (COMException e) { Trace.WriteLine("Exception : " + e.Message); returnValue = e.ErrorCode; } return returnValue; }
internal void DropFilesOrFolders(string[] filesDropped, HierarchyNode ontoNode) { var waitDialog = (IVsThreadedWaitDialog)Site.GetService(typeof(SVsThreadedWaitDialog)); int waitResult = waitDialog.StartWaitDialog( "Adding files and folders...", "Adding files to your project, this may take several seconds...", null, 0, null, null ); try { ontoNode = ontoNode.GetDragTargetHandlerNode(); string nodePath = ontoNode.FullPathToChildren; bool droppingExistingDirectory = true; foreach (var droppedFile in filesDropped) { if (!Directory.Exists(droppedFile) || !String.Equals(Path.GetDirectoryName(droppedFile), nodePath, StringComparison.OrdinalIgnoreCase)) { droppingExistingDirectory = false; break; } } if (droppingExistingDirectory) { // we're dragging a directory/directories that already exist // into the location where they exist, we can do this via a fast path, // and pop up a nice progress bar. AddExistingDirectories(ontoNode, filesDropped); } else { foreach (var droppedFile in filesDropped) { if (Directory.Exists(droppedFile) && CommonUtils.IsSubpathOf(droppedFile, nodePath)) { int cancelled = 0; waitDialog.EndWaitDialog(ref cancelled); waitResult = VSConstants.E_FAIL; // don't end twice Utilities.ShowMessageBox( Site, SR.GetString(SR.CannotAddFolderAsDescendantOfSelf, CommonUtils.GetFileOrDirectoryName(droppedFile)), null, OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); return; } } // This is the code path when source is windows explorer VSADDRESULT[] vsaddresults = new VSADDRESULT[1]; vsaddresults[0] = VSADDRESULT.ADDRESULT_Failure; int addResult = AddItem(ontoNode.ID, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, (uint)filesDropped.Length, filesDropped, IntPtr.Zero, vsaddresults); if (addResult != VSConstants.S_OK && addResult != VSConstants.S_FALSE && addResult != (int)OleConstants.OLECMDERR_E_CANCELED && vsaddresults[0] != VSADDRESULT.ADDRESULT_Success) { ErrorHandler.ThrowOnFailure(addResult); } } } finally { if (ErrorHandler.Succeeded(waitResult)) { int cancelled = 0; waitDialog.EndWaitDialog(ref cancelled); } } }
/// <summary> /// This is used to recursively add a folder from an other project. /// Note that while we copy the folder content completely, we only /// add to the project items which are part of the source project. /// </summary> /// <param name="folderToAdd">Project reference (from data object) using the format: {Guid}|project|folderPath</param> /// <param name="targetNode">Node to add the new folder to</param> protected internal virtual bool AddFolderFromOtherProject(string folderToAdd, HierarchyNode targetNode, bool drop) { Utilities.ArgumentNotNullOrEmpty(folderToAdd, "folderToAdd"); Utilities.ArgumentNotNull("targetNode", targetNode); var targetFolderNode = targetNode.GetDragTargetHandlerNode(); // Split the reference in its 3 parts int index1 = Guid.Empty.ToString("B").Length; if (index1 + 1 >= folderToAdd.Length) throw new ArgumentOutOfRangeException("folderToAdd"); // Get the Guid string guidString = folderToAdd.Substring(1, index1 - 2); Guid projectInstanceGuid = new Guid(guidString); // Get the project path int index2 = folderToAdd.IndexOf('|', index1 + 1); if (index2 < 0 || index2 + 1 >= folderToAdd.Length) throw new ArgumentOutOfRangeException("folderToAdd"); // Finally get the source path string folder = folderToAdd.Substring(index2 + 1); // Get the target path string folderName = Path.GetFileName(Path.GetDirectoryName(folder)); string targetPath = Path.Combine(GetBaseDirectoryForAddingFiles(targetFolderNode), folderName); // Retrieve the project from which the items are being copied IVsHierarchy sourceHierarchy; IVsSolution solution = (IVsSolution)GetService(typeof(SVsSolution)); ErrorHandler.ThrowOnFailure(solution.GetProjectOfGuid(ref projectInstanceGuid, out sourceHierarchy)); // Then retrieve the item ID of the item to copy uint itemID = VSConstants.VSITEMID_ROOT; ErrorHandler.ThrowOnFailure(sourceHierarchy.ParseCanonicalName(folder, out itemID)); string name = folderName; // Ensure we don't end up in an endless recursion if (Utilities.IsSameComObject(this, sourceHierarchy)) { // copy file onto its self, we should make a copy of the folder if (String.Equals(folder, targetNode.GetMkDocument(), StringComparison.OrdinalIgnoreCase)) { if (drop) { // cancelled drag and drop return false; } string newDir; string baseName = folder; folder = CommonUtils.TrimEndSeparator(folder); int copyCount = 0; do { name = folderName + " - Copy"; if (copyCount != 0) { name += " (" + copyCount + ")"; } copyCount++; newDir = Path.Combine(Path.GetDirectoryName(folder), name); } while (Directory.Exists(newDir)); targetPath = newDir; targetFolderNode = targetNode.Parent; } else { HierarchyNode cursorNode = targetFolderNode; while (cursorNode != null) { if (String.Equals(folder, cursorNode.GetMkDocument(), StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException(String.Format("Cannot copy '{0}'. The destination folder is a subfolder of the source folder.", folderName)); } cursorNode = cursorNode.Parent; } } } // Recursively copy the directory to the new location Utilities.RecursivelyCopyDirectory(folder, targetPath); // Now walk the source project hierarchy to see which node needs to be added. WalkSourceProjectAndAdd(sourceHierarchy, itemID, targetFolderNode, false, name); return true; }