Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(997)

Side by Side Diff: obsolete/Microsoft.VisualStudio.Project/ProjectNode.CopyPaste.cs

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /// Copyright (c) Microsoft Corporation. All rights reserved.
2
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.IO;
9 using System.Runtime.InteropServices;
10 using System.Security.Permissions;
11 using System.Text;
12 using Microsoft.VisualStudio;
13 using Microsoft.VisualStudio.OLE.Interop;
14 using Microsoft.VisualStudio.Shell;
15 using Microsoft.VisualStudio.Shell.Interop;
16 using IOleDataObject = Microsoft.VisualStudio.OLE.Interop.IDataObject;
17 using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants;
18
19 namespace Microsoft.VisualStudio.Project
20 {
21 /// <summary>
22 /// Manages the CopyPaste and Drag and Drop scenarios for a Project.
23 /// </summary>
24 /// <remarks>This is a partial class.</remarks>
25 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainabil ity", "CA1506:AvoidExcessiveClassCoupling")]
26 public partial class ProjectNode : IVsUIHierWinClipboardHelperEvents
27 {
28 #region fields
29 private uint copyPasteCookie;
30 private DropDataType dropDataType;
31 #endregion
32
33 #region override of IVsHierarchyDropDataTarget methods
34 /// <summary>
35 /// Called as soon as the mouse drags an item over a new hierarc hy or hierarchy window
36 /// </summary>
37 /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param>
38 /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param>
39 /// <param name="itemid">Item identifier for the item currently being dragged</param>
40 /// <param name="pdwEffect">On entry, a pointer to the current D ropEffect. On return, must contain the new valid DropEffect</param>
41 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code.</returns>
42 public override int DragEnter(IOleDataObject pDataObject, uint g rfKeyState, uint itemid, ref uint pdwEffect)
43 {
44 pdwEffect = (uint)DropEffect.None;
45
46 if(this.SourceDraggedOrCutOrCopied)
47 {
48 return VSConstants.S_OK;
49 }
50
51 this.dropDataType = QueryDropDataType(pDataObject);
52 if(this.dropDataType != DropDataType.None)
53 {
54 pdwEffect = (uint)this.QueryDropEffect(this.drop DataType, grfKeyState);
55 }
56
57 return VSConstants.S_OK;
58 }
59
60 /// <summary>
61 /// Called when one or more items are dragged out of the hierarc hy or hierarchy window, or when the drag-and-drop operation is cancelled or comp leted.
62 /// </summary>
63 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code.</returns>
64 public override int DragLeave()
65 {
66 this.dropDataType = DropDataType.None;
67 return VSConstants.S_OK;
68 }
69
70 /// <summary>
71 /// Called when one or more items are dragged over the target hi erarchy or hierarchy window.
72 /// </summary>
73 /// <param name="grfKeyState">Current state of the keyboard keys and the mouse modifier buttons. See <seealso cref="IVsHierarchyDropDataTarget"/ ></param>
74 /// <param name="itemid">Item identifier of the drop data target over which the item is being dragged</param>
75 /// <param name="pdwEffect"> On entry, reference to the value of the pdwEffect parameter of the IVsHierarchy object, identifying all effects tha t the hierarchy supports.
76 /// On return, the pdwEffect parameter must contain one of the e ffect flags that indicate the result of the drop operation. For a list of pwdEff ects values, see <seealso cref="DragEnter"/></param>
77 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code.</returns>
78 public override int DragOver(uint grfKeyState, uint itemid, ref uint pdwEffect)
79 {
80 pdwEffect = (uint)DropEffect.None;
81
82 // Dragging items to a project that is being debugged is not supported
83 // (see VSWhidbey 144785)
84 DBGMODE dbgMode = VsShellUtilities.GetDebugMode(this.Sit e) & ~DBGMODE.DBGMODE_EncMask;
85 if(dbgMode == DBGMODE.DBGMODE_Run || dbgMode == DBGMODE. DBGMODE_Break)
86 {
87 return VSConstants.S_OK;
88 }
89
90 if(this.isClosed || this.site == null)
91 {
92 return VSConstants.E_UNEXPECTED;
93 }
94
95 // We should also analyze if the node being dragged over can accept the drop.
96 if(!this.CanTargetNodeAcceptDrop(itemid))
97 {
98 return VSConstants.E_NOTIMPL;
99 }
100
101 if(this.dropDataType != DropDataType.None)
102 {
103 pdwEffect = (uint)this.QueryDropEffect(this.drop DataType, grfKeyState);
104 }
105
106 return VSConstants.S_OK;
107 }
108
109 /// <summary>
110 /// Called when one or more items are dropped into the target hi erarchy or hierarchy window when the mouse button is released.
111 /// </summary>
112 /// <param name="pDataObject">Reference to the IDataObject inter face on the item being dragged. This data object contains the data being transfe rred in the drag-and-drop operation.
113 /// If the drop occurs, then this data object (item) is incorpor ated into the target hierarchy or hierarchy window.</param>
114 /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See <seealso cref="IVsHierarchyDropDataTarget"/></param >
115 /// <param name="itemid">Item identifier of the drop data target over which the item is being dragged</param>
116 /// <param name="pdwEffect">Visual effects associated with the d rag-and drop-operation, such as a cursor, bitmap, and so on.
117 /// The value of dwEffects passed to the source object via the O nDropNotify method is the value of pdwEffects returned by the Drop method</param >
118 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
119 public override int Drop(IOleDataObject pDataObject, uint grfKey State, uint itemid, ref uint pdwEffect)
120 {
121 if(pDataObject == null)
122 {
123 return VSConstants.E_INVALIDARG;
124 }
125
126 pdwEffect = (uint)DropEffect.None;
127
128 // Get the node that is being dragged over and ask it wh ich node should handle this call
129 HierarchyNode targetNode = NodeFromItemId(itemid);
130 if(targetNode != null)
131 {
132 targetNode = targetNode.GetDragTargetHandlerNode ();
133 }
134 else
135 {
136 // There is no target node. The drop can not be completed.
137 return VSConstants.S_FALSE;
138 }
139
140 int returnValue;
141 try
142 {
143 DropDataType dropDataType = DropDataType.None;
144 dropDataType = ProcessSelectionDataObject(pDataO bject, targetNode);
145 pdwEffect = (uint)this.QueryDropEffect(dropDataT ype, grfKeyState);
146
147 // If it is a drop from windows and we get any k ind of error we return S_FALSE and dropeffect none. This
148 // prevents bogus messages from the shell from b eing displayed
149 returnValue = (dropDataType != DropDataType.Shel l) ? VSConstants.E_FAIL : VSConstants.S_OK;
150 }
151 catch(System.IO.FileNotFoundException e)
152 {
153 Trace.WriteLine("Exception : " + e.Message);
154
155 if(!Utilities.IsInAutomationFunction(this.Site))
156 {
157 string message = e.Message;
158 string title = string.Empty;
159 OLEMSGICON icon = OLEMSGICON.OLEMSGICON_ CRITICAL;
160 OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEM SGBUTTON_OK;
161 OLEMSGDEFBUTTON defaultButton = OLEMSGDE FBUTTON.OLEMSGDEFBUTTON_FIRST;
162 VsShellUtilities.ShowMessageBox(this.Sit e, title, message, icon, buttons, defaultButton);
163 }
164
165 returnValue = VSConstants.E_FAIL;
166 }
167
168 return returnValue;
169 }
170 #endregion
171
172 #region override of IVsHierarchyDropDataSource2 methods
173 /// <summary>
174 /// Returns information about one or more of the items being dra gged
175 /// </summary>
176 /// <param name="pdwOKEffects">Pointer to a DWORD value describi ng the effects displayed while the item is being dragged,
177 /// such as cursor icons that change during the drag-and-drop op eration.
178 /// For example, if the item is dragged over an invalid target p oint
179 /// (such as the item's original location), the cursor icon chan ges to a circle with a line through it.
180 /// Similarly, if the item is dragged over a valid target point, the cursor icon changes to a file or folder.</param>
181 /// <param name="ppDataObject">Pointer to the IDataObject interf ace on the item being dragged.
182 /// This data object contains the data being transferred in the drag-and-drop operation.
183 /// If the drop occurs, then this data object (item) is incorpor ated into the target hierarchy or hierarchy window.</param>
184 /// <param name="ppDropSource">Pointer to the IDropSource interf ace of the item being dragged.</param>
185 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code.</returns>
186 public override int GetDropInfo(out uint pdwOKEffects, out IOleD ataObject ppDataObject, out IDropSource ppDropSource)
187 {
188 //init out params
189 pdwOKEffects = (uint)DropEffect.None;
190 ppDataObject = null;
191 ppDropSource = null;
192
193 IOleDataObject dataObject = PackageSelectionDataObject(f alse);
194 if(dataObject == null)
195 {
196 return VSConstants.E_NOTIMPL;
197 }
198
199 this.SourceDraggedOrCutOrCopied = true;
200
201 pdwOKEffects = (uint)(DropEffect.Move | DropEffect.Copy) ;
202
203 ppDataObject = dataObject;
204 return VSConstants.S_OK;
205 }
206
207 /// <summary>
208 /// Notifies clients that the dragged item was dropped.
209 /// </summary>
210 /// <param name="fDropped">If true, then the dragged item was dr opped on the target. If false, then the drop did not occur.</param>
211 /// <param name="dwEffects">Visual effects associated with the d rag-and-drop operation, such as cursors, bitmaps, and so on.
212 /// The value of dwEffects passed to the source object via OnDro pNotify method is the value of pdwEffects returned by Drop method.</param>
213 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
214 public override int OnDropNotify(int fDropped, uint dwEffects)
215 {
216 if(!this.SourceDraggedOrCutOrCopied)
217 {
218 return VSConstants.S_FALSE;
219 }
220
221 this.CleanupSelectionDataObject(fDropped != 0, false, dw Effects == (uint)DropEffect.Move);
222
223 this.SourceDraggedOrCutOrCopied = false;
224
225 return VSConstants.S_OK;
226 }
227
228 /// <summary>
229 /// Allows the drag source to prompt to save unsaved items being dropped.
230 /// Notifies the source hierarchy that information dragged from it is about to be dropped on a target.
231 /// This method is called immediately after the mouse button is released on a drop.
232 /// </summary>
233 /// <param name="o">Reference to the IDataObject interface on th e item being dragged.
234 /// This data object contains the data being transferred in the drag-and-drop operation.
235 /// If the drop occurs, then this data object (item) is incorpor ated into the hierarchy window of the new hierarchy.</param>
236 /// <param name="dwEffect">Current state of the keyboard and the mouse modifier keys.</param>
237 /// <param name="fCancelDrop">If true, then the drop is cancelle d by the source hierarchy. If false, then the drop can continue.</param>
238 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
239 public override int OnBeforeDropNotify(IOleDataObject o, uint dw Effect, out int fCancelDrop)
240 {
241 // If there is nothing to be dropped just return that dr op should be cancelled.
242 if(this.ItemsDraggedOrCutOrCopied == null)
243 {
244 fCancelDrop = 1;
245 return VSConstants.S_OK;
246 }
247
248 fCancelDrop = 0;
249 bool dirty = false;
250 foreach(HierarchyNode node in this.ItemsDraggedOrCutOrCo pied)
251 {
252 bool isDirty, isOpen, isOpenedByUs;
253 uint docCookie;
254 IVsPersistDocData ppIVsPersistDocData;
255 DocumentManager manager = node.GetDocumentManage r();
256 if(manager != null)
257 {
258 manager.GetDocInfo(out isOpen, out isDir ty, out isOpenedByUs, out docCookie, out ppIVsPersistDocData);
259 if(isDirty && isOpenedByUs)
260 {
261 dirty = true;
262 break;
263 }
264 }
265 }
266
267 // if there are no dirty docs we are ok to proceed
268 if(!dirty)
269 {
270 return VSConstants.S_OK;
271 }
272
273 // Prompt to save if there are dirty docs
274 string message = SR.GetString(SR.SaveModifiedDocuments, CultureInfo.CurrentUICulture);
275 string title = string.Empty;
276 OLEMSGICON icon = OLEMSGICON.OLEMSGICON_WARNING;
277 OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_YESNOCA NCEL;
278 OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDE FBUTTON_FIRST;
279 int result = VsShellUtilities.ShowMessageBox(Site, title , message, icon, buttons, defaultButton);
280 switch(result)
281 {
282 case NativeMethods.IDYES:
283 break;
284
285 case NativeMethods.IDNO:
286 return VSConstants.S_OK;
287
288 case NativeMethods.IDCANCEL: goto default;
289
290 default:
291 fCancelDrop = 1;
292 return VSConstants.S_OK;
293 }
294
295 // Save all dirty documents
296 foreach(HierarchyNode node in this.ItemsDraggedOrCutOrCo pied)
297 {
298 DocumentManager manager = node.GetDocumentManage r();
299 if(manager != null)
300 {
301 manager.Save(true);
302 }
303 }
304
305 return VSConstants.S_OK;
306 }
307
308 #endregion
309
310 #region IVsUIHierWinClipboardHelperEvents Members
311 /// <summary>
312 /// Called after your cut/copied items has been pasted
313 /// </summary>
314 ///<param name="wasCut">If true, then the IDataObject has been s uccessfully pasted into a target hierarchy.
315 /// If false, then the cut or copy operation was cancelled.</par am>
316 /// <param name="dropEffect">Visual effects associated with the drag and drop operation, such as cursors, bitmaps, and so on.
317 /// These should be the same visual effects used in OnDropNotify </param>
318 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
319 public virtual int OnPaste(int wasCut, uint dropEffect)
320 {
321 if(!this.SourceDraggedOrCutOrCopied)
322 {
323 return VSConstants.S_FALSE;
324 }
325
326 if(dropEffect == (uint)DropEffect.None)
327 {
328 return OnClear(wasCut);
329 }
330
331 this.CleanupSelectionDataObject(false, wasCut != 0, drop Effect == (uint)DropEffect.Move);
332 this.SourceDraggedOrCutOrCopied = false;
333 return VSConstants.S_OK;
334 }
335
336 /// <summary>
337 /// Called when your cut/copied operation is canceled
338 /// </summary>
339 /// <param name="wasCut">This flag informs the source that the C ut method was called (true),
340 /// rather than Copy (false), so the source knows whether to "un -cut-highlight" the items that were cut.</param>
341 /// <returns>If the method succeeds, it returns S_OK. If it fail s, it returns an error code. </returns>
342 public virtual int OnClear(int wasCut)
343 {
344 if(!this.SourceDraggedOrCutOrCopied)
345 {
346 return VSConstants.S_FALSE;
347 }
348
349 this.CleanupSelectionDataObject(false, wasCut != 0, fals e, true);
350 this.SourceDraggedOrCutOrCopied = false;
351 return VSConstants.S_OK;
352 }
353 #endregion
354
355 #region virtual methods
356 /// <summary>
357 /// Determines if a node can accept drop opertaion.
358 /// </summary>
359 /// <param name="itemid">The id of the node.</param>
360 /// <returns>true if the node acceots drag operation.</returns>
361 protected internal virtual bool CanTargetNodeAcceptDrop(uint ite mId)
362 {
363 HierarchyNode targetNode = NodeFromItemId(itemId);
364 if(targetNode is ReferenceContainerNode || targetNode is ReferenceNode)
365 {
366 return false;
367 }
368 else
369 {
370 return true;
371 }
372 }
373
374 /// <summary>
375 /// Returns a dataobject from selected nodes
376 /// </summary>
377 /// <param name="cutHighlightItems">boolean that defines if the selected items must be cut</param>
378 /// <returns>data object for selected items</returns>
379 internal virtual DataObject PackageSelectionDataObject(bool cutH ighlightItems)
380 {
381 this.CleanupSelectionDataObject(false, false, false);
382 StringBuilder sb = new StringBuilder();
383
384 DataObject dataObject = null;
385
386 try
387 {
388 IList<HierarchyNode> selectedNodes = this.GetSel ectedNodes();
389 if(selectedNodes != null)
390 {
391 this.InstantiateItemsDraggedOrCutOrCopie dList();
392
393 StringBuilder selectionContent = null;
394
395 // If there is a selection package the d ata
396 if(selectedNodes.Count > 1)
397 {
398 foreach(HierarchyNode node in se lectedNodes)
399 {
400 selectionContent = node. PrepareSelectedNodesForClipBoard();
401 if(selectionContent != n ull)
402 {
403 sb.Append(select ionContent);
404 }
405 }
406 }
407 else if(selectedNodes.Count == 1)
408 {
409 HierarchyNode selectedNode = sel ectedNodes[0];
410 selectionContent = selectedNode. PrepareSelectedNodesForClipBoard();
411 if(selectionContent != null)
412 {
413 sb.Append(selectionConte nt);
414 }
415 }
416 }
417
418 // Add the project items first.
419 IntPtr ptrToItems = this.PackageSelectionData(sb , false);
420 if(ptrToItems == IntPtr.Zero)
421 {
422 return null;
423 }
424
425 FORMATETC fmt = DragDropHelper.CreateFormatEtc(D ragDropHelper.CF_VSSTGPROJECTITEMS);
426 dataObject = new DataObject();
427 dataObject.SetData(fmt, ptrToItems);
428
429 // Now add the project path that sourced data. W e just write the project file path.
430 IntPtr ptrToProjectPath = this.PackageSelectionD ata(new StringBuilder(this.GetMkDocument()), true);
431
432 if(ptrToProjectPath != IntPtr.Zero)
433 {
434 dataObject.SetData(DragDropHelper.Create FormatEtc(DragDropHelper.CF_VSPROJECTCLIPDESCRIPTOR), ptrToProjectPath);
435 }
436
437 if(cutHighlightItems)
438 {
439 bool first = true;
440 IVsUIHierarchyWindow w = UIHierarchyUtil ities.GetUIHierarchyWindow(this.site, HierarchyNode.SolutionExplorer);
441
442 foreach(HierarchyNode node in this.Items DraggedOrCutOrCopied)
443 {
444 ErrorHandler.ThrowOnFailure(w.Ex pandItem((IVsUIHierarchy)this, node.ID, first ? EXPANDFLAGS.EXPF_CutHighlightIte m : EXPANDFLAGS.EXPF_AddCutHighlightItem));
445 first = false;
446 }
447 }
448 }
449 catch(COMException e)
450 {
451 Trace.WriteLine("Exception : " + e.Message);
452
453 dataObject = null;
454 }
455
456 return dataObject;
457 }
458
459
460 /// <summary>
461 /// This is used to recursively add a folder from an other proje ct.
462 /// Note that while we copy the folder content completely, we on ly
463 /// add to the project items which are part of the source projec t.
464 /// </summary>
465 /// <param name="folderToAdd">Project reference (from data objec t) using the format: {Guid}|project|folderPath</param>
466 /// <param name="targetNode">Node to add the new folder to</para m>
467 protected internal virtual void AddFolderFromOtherProject(string folderToAdd, HierarchyNode targetNode)
468 {
469 if(String.IsNullOrEmpty(folderToAdd))
470 throw new ArgumentNullException("folderToAdd");
471 if(targetNode == null)
472 throw new ArgumentNullException("targetNode");
473
474 // Split the reference in its 3 parts
475 int index1 = Guid.Empty.ToString("B").Length;
476 if(index1 + 1 >= folderToAdd.Length)
477 throw new ArgumentOutOfRangeException("folderToA dd");
478
479 // Get the Guid
480 string guidString = folderToAdd.Substring(1, index1 - 2) ;
481 Guid projectInstanceGuid = new Guid(guidString);
482
483 // Get the project path
484 int index2 = folderToAdd.IndexOf('|', index1 + 1);
485 if(index2 < 0 || index2 + 1 >= folderToAdd.Length)
486 throw new ArgumentOutOfRangeException("folderToA dd");
487
488 // Finally get the source path
489 string folder = folderToAdd.Substring(index2 + 1);
490
491 // Get the target path
492 string folderName = Path.GetFileName(Path.GetDirectoryNa me(folder));
493 string targetPath = Path.Combine(GetBaseDirectoryForAddi ngFiles(targetNode), folderName);
494
495 // Recursively copy the directory to the new location
496 Utilities.RecursivelyCopyDirectory(folder, targetPath);
497
498 // Retrieve the project from which the items are being c opied
499 IVsHierarchy sourceHierarchy;
500 IVsSolution solution = (IVsSolution)GetService(typeof(SV sSolution));
501 ErrorHandler.ThrowOnFailure(solution.GetProjectOfGuid(re f projectInstanceGuid, out sourceHierarchy));
502
503 // Then retrieve the item ID of the item to copy
504 uint itemID = VSConstants.VSITEMID_ROOT;
505 ErrorHandler.ThrowOnFailure(sourceHierarchy.ParseCanonic alName(folder, out itemID));
506
507 // Ensure we don't end up in an endless recursion
508 if(Utilities.IsSameComObject(this, sourceHierarchy))
509 {
510 HierarchyNode cursorNode = targetNode;
511 while(cursorNode != null)
512 {
513 if(String.Compare(folder, cursorNode.Get MkDocument(), StringComparison.OrdinalIgnoreCase) == 0)
514 throw new Exception();
515 cursorNode = cursorNode.Parent;
516 }
517 }
518
519 // Now walk the source project hierarchy to see which no de needs to be added.
520 WalkSourceProjectAndAdd(sourceHierarchy, itemID, targetN ode, false);
521 }
522
523 /// <summary>
524 /// Recursive method that walk a hierarchy and add items it find to our project.
525 /// Note that this is meant as an helper to the Copy&Paste/Drag& Drop functionality.
526 /// </summary>
527 /// <param name="sourceHierarchy">Hierarchy to walk</param>
528 /// <param name="itemId">Item ID where to start walking the hier archy</param>
529 /// <param name="targetNode">Node to start adding to</param>
530 /// <param name="addSibblings">Typically false on first call and true after that</param>
531 protected virtual void WalkSourceProjectAndAdd(IVsHierarchy sour ceHierarchy, uint itemId, HierarchyNode targetNode, bool addSiblings)
532 {
533 // Before we start the walk, add the current node
534 object variant = null;
535 HierarchyNode newNode = targetNode;
536 if(itemId != VSConstants.VSITEMID_NIL)
537 {
538 // Calculate the corresponding path in our proje ct
539 string source;
540 ErrorHandler.ThrowOnFailure(((IVsProject)sourceH ierarchy).GetMkDocument(itemId, out source));
541 string name = Path.GetFileName(source.TrimEnd(ne w char[] { '/', '\\' }));
542 string targetPath = Path.Combine(GetBaseDirector yForAddingFiles(targetNode), name);
543
544 // See if this is a linked item (file can be lin ked, not folders)
545 ErrorHandler.ThrowOnFailure(sourceHierarchy.GetP roperty(itemId, (int)__VSHPROPID.VSHPROPID_BrowseObject, out variant), VSConstan ts.E_NOTIMPL);
546 VSLangProj.FileProperties fileProperties = varia nt as VSLangProj.FileProperties;
547 if(fileProperties != null && fileProperties.IsLi nk)
548 {
549 // Since we don't support linked item, w e make a copy of the file into our storage where it would have been linked
550 File.Copy(source, targetPath, true);
551 }
552
553 newNode = AddNodeIfTargetExistInStorage(targetNo de, name, targetPath);
554
555
556 // Start with child nodes (depth first)
557 variant = null;
558 ErrorHandler.ThrowOnFailure(sourceHierarchy.GetP roperty(itemId, (int)__VSHPROPID.VSHPROPID_FirstVisibleChild, out variant));
559 uint currentItemID = (uint)(int)variant;
560 WalkSourceProjectAndAdd(sourceHierarchy, current ItemID, newNode, true);
561
562 if(addSiblings)
563 {
564 // Then look at siblings
565 currentItemID = itemId;
566 while(currentItemID != VSConstants.VSITE MID_NIL)
567 {
568 variant = null;
569 ErrorHandler.ThrowOnFailure(sour ceHierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_NextVisibleSibling, o ut variant));
570 currentItemID = (uint)(int)varia nt;
571 WalkSourceProjectAndAdd(sourceHi erarchy, currentItemID, targetNode, true);
572 }
573 }
574 }
575 }
576
577 /// <summary>
578 /// Add an existing item (file/folder) to the project if it alre ady exist in our storage.
579 /// </summary>
580 /// <param name="parentNode">Node to that this item to</param>
581 /// <param name="name">Name of the item being added</param>
582 /// <param name="targetPath">Path of the item being added</param >
583 /// <returns>Node that was added</returns>
584 protected virtual HierarchyNode AddNodeIfTargetExistInStorage(Hi erarchyNode parentNode, string name, string targetPath)
585 {
586 HierarchyNode newNode = parentNode;
587 // If the file/directory exist, add a node for it
588 if(File.Exists(targetPath))
589 {
590 VSADDRESULT[] result = new VSADDRESULT[1];
591 ErrorHandler.ThrowOnFailure(this.AddItem(parentN ode.ID, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, name, 1, new string[] { targetP ath }, IntPtr.Zero, result));
592 if(result[0] != VSADDRESULT.ADDRESULT_Success)
593 throw new Exception();
594 newNode = this.FindChild(targetPath);
595 if(newNode == null)
596 throw new Exception();
597 }
598 else if(Directory.Exists(targetPath))
599 {
600 newNode = this.CreateFolderNodes(targetPath);
601 }
602 return newNode;
603 }
604 #endregion
605
606 #region non-virtual methods
607 /// <summary>
608 /// Handle the Cut operation to the clipboard
609 /// </summary>
610 protected internal override int CutToClipboard()
611 {
612 int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPO RTED;
613 try
614 {
615 this.RegisterClipboardNotifications(true);
616
617 // Create our data object and change the selecti on to show item(s) being cut
618 IOleDataObject dataObject = this.PackageSelectio nDataObject(true);
619 if(dataObject != null)
620 {
621 this.SourceDraggedOrCutOrCopied = true;
622
623 // Add our cut item(s) to the clipboard
624 ErrorHandler.ThrowOnFailure(UnsafeNative Methods.OleSetClipboard(dataObject));
625
626 // Inform VS (UiHierarchyWindow) of the cut
627 IVsUIHierWinClipboardHelper clipboardHel per = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper ));
628 if(clipboardHelper == null)
629 {
630 return VSConstants.E_FAIL;
631 }
632
633 returnValue = ErrorHandler.ThrowOnFailur e(clipboardHelper.Cut(dataObject));
634 }
635 }
636 catch(COMException e)
637 {
638 Trace.WriteLine("Exception : " + e.Message);
639 returnValue = e.ErrorCode;
640 }
641
642 return returnValue;
643 }
644
645 /// <summary>
646 /// Handle the Copy operation to the clipboard
647 /// </summary>
648 protected internal override int CopyToClipboard()
649 {
650 int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPO RTED;
651 try
652 {
653 this.RegisterClipboardNotifications(true);
654
655 // Create our data object and change the selecti on to show item(s) being copy
656 IOleDataObject dataObject = this.PackageSelectio nDataObject(false);
657 if(dataObject != null)
658 {
659 this.SourceDraggedOrCutOrCopied = true;
660
661 // Add our copy item(s) to the clipboard
662 ErrorHandler.ThrowOnFailure(UnsafeNative Methods.OleSetClipboard(dataObject));
663
664 // Inform VS (UiHierarchyWindow) of the copy
665 IVsUIHierWinClipboardHelper clipboardHel per = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper ));
666 if(clipboardHelper == null)
667 {
668 return VSConstants.E_FAIL;
669 }
670 returnValue = ErrorHandler.ThrowOnFailur e(clipboardHelper.Copy(dataObject));
671 }
672 }
673 catch(COMException e)
674 {
675 Trace.WriteLine("Exception : " + e.Message);
676 returnValue = e.ErrorCode;
677 }
678 catch(ArgumentException e)
679 {
680 Trace.WriteLine("Exception : " + e.Message);
681 returnValue = Marshal.GetHRForException(e);
682 }
683
684 return returnValue;
685 }
686
687 /// <summary>
688 /// Handle the Paste operation to a targetNode
689 /// </summary>
690 protected internal override int PasteFromClipboard(HierarchyNode targetNode)
691 {
692 int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPO RTED;
693
694 //Get the clipboardhelper service and use it after proce ssing dataobject
695 IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHier WinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper));
696 if(clipboardHelper == null)
697 {
698 return VSConstants.E_FAIL;
699 }
700
701 try
702 {
703 //Get dataobject from clipboard
704 IOleDataObject dataObject = null;
705 ErrorHandler.ThrowOnFailure(UnsafeNativeMethods. OleGetClipboard(out dataObject));
706 if(dataObject == null)
707 {
708 return VSConstants.E_UNEXPECTED;
709 }
710
711 DropEffect dropEffect = DropEffect.None;
712 DropDataType dropDataType = DropDataType.None;
713 try
714 {
715 dropDataType = this.ProcessSelectionData Object(dataObject, targetNode.GetDragTargetHandlerNode());
716 dropEffect = this.QueryDropEffect(dropDa taType, 0);
717 }
718 catch(ExternalException e)
719 {
720 Trace.WriteLine("Exception : " + e.Messa ge);
721
722 // If it is a drop from windows and we g et any kind of error ignore it. This
723 // prevents bogus messages from the shel l from being displayed
724 if(dropDataType != DropDataType.Shell)
725 {
726 throw;
727 }
728 }
729 finally
730 {
731 // Inform VS (UiHierarchyWindow) of the paste
732 returnValue = clipboardHelper.Paste(data Object, (uint)dropEffect);
733 }
734 }
735 catch(COMException e)
736 {
737 Trace.WriteLine("Exception : " + e.Message);
738
739 returnValue = e.ErrorCode;
740 }
741
742 return returnValue;
743 }
744
745 /// <summary>
746 /// Determines if the paste command should be allowed.
747 /// </summary>
748 /// <returns></returns>
749 protected internal override bool AllowPasteCommand()
750 {
751 IOleDataObject dataObject = null;
752 try
753 {
754 ErrorHandler.ThrowOnFailure(UnsafeNativeMethods. OleGetClipboard(out dataObject));
755 if(dataObject == null)
756 {
757 return false;
758 }
759
760 // First see if this is a set of storage based i tems
761 FORMATETC format = DragDropHelper.CreateFormatEt c((ushort)DragDropHelper.CF_VSSTGPROJECTITEMS);
762 if(dataObject.QueryGetData(new FORMATETC[] { for mat }) == VSConstants.S_OK)
763 return true;
764 // Try reference based items
765 format = DragDropHelper.CreateFormatEtc((ushort) DragDropHelper.CF_VSREFPROJECTITEMS);
766 if(dataObject.QueryGetData(new FORMATETC[] { for mat }) == VSConstants.S_OK)
767 return true;
768 // Try windows explorer files format
769 format = DragDropHelper.CreateFormatEtc((ushort) NativeMethods.CF_HDROP);
770 return (dataObject.QueryGetData(new FORMATETC[] { format }) == VSConstants.S_OK);
771 }
772 // We catch External exceptions since it might be that i t is not our data on the clipboard.
773 catch(ExternalException e)
774 {
775 Trace.WriteLine("Exception :" + e.Message);
776 return false;
777 }
778 }
779
780 /// <summary>
781 /// Register/Unregister for Clipboard events for the UiHierarchy Window (solution explorer)
782 /// </summary>
783 /// <param name="register">true for register, false for unregist er</param>
784 protected internal override void RegisterClipboardNotifications( bool register)
785 {
786 // Get the UiHierarchy window clipboard helper service
787 IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHier WinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper));
788 if(clipboardHelper == null)
789 {
790 return;
791 }
792
793 if(register && this.copyPasteCookie == 0)
794 {
795 // Register
796 ErrorHandler.ThrowOnFailure(clipboardHelper.Advi seClipboardHelperEvents(this, out this.copyPasteCookie));
797 Debug.Assert(this.copyPasteCookie != 0, "AdviseC lipboardHelperEvents returned an invalid cookie");
798 }
799 else if(!register && this.copyPasteCookie != 0)
800 {
801 // Unregister
802 ErrorHandler.ThrowOnFailure(clipboardHelper.Unad viseClipboardHelperEvents(this.copyPasteCookie));
803 this.copyPasteCookie = 0;
804 }
805 }
806
807 /// <summary>
808 /// Process dataobject from Drag/Drop/Cut/Copy/Paste operation
809 /// </summary>
810 /// <remarks>The targetNode is set if the method is called from a drop operation, otherwise it is null</remarks>
811 internal DropDataType ProcessSelectionDataObject(IOleDataObject dataObject, HierarchyNode targetNode)
812 {
813 DropDataType dropDataType = DropDataType.None;
814 bool isWindowsFormat = false;
815
816 // Try to get it as a directory based project.
817 List<string> filesDropped = DragDropHelper.GetDroppedFil es(DragDropHelper.CF_VSSTGPROJECTITEMS, dataObject, out dropDataType);
818 if(filesDropped.Count == 0)
819 {
820 filesDropped = DragDropHelper.GetDroppedFiles(Dr agDropHelper.CF_VSREFPROJECTITEMS, dataObject, out dropDataType);
821 }
822 if(filesDropped.Count == 0)
823 {
824 filesDropped = DragDropHelper.GetDroppedFiles(Na tiveMethods.CF_HDROP, dataObject, out dropDataType);
825 isWindowsFormat = (filesDropped.Count > 0);
826 }
827
828 if(dropDataType != DropDataType.None && filesDropped.Cou nt > 0)
829 {
830 string[] filesDroppedAsArray = filesDropped.ToAr ray();
831
832 HierarchyNode node = (targetNode == null) ? this : targetNode;
833
834 // For directory based projects the content of t he clipboard is a double-NULL terminated list of Projref strings.
835 if(isWindowsFormat)
836 {
837 // This is the code path when source is windows explorer
838 VSADDRESULT[] vsaddresults = new VSADDRE SULT[1];
839 vsaddresults[0] = VSADDRESULT.ADDRESULT_ Failure;
840 int addResult = AddItem(node.ID, VSADDIT EMOPERATION.VSADDITEMOP_OPENFILE, null, (uint)filesDropped.Count, filesDroppedAs Array, IntPtr.Zero, vsaddresults);
841 if(addResult != VSConstants.S_OK && addR esult != VSConstants.S_FALSE && addResult != (int)OleConstants.OLECMDERR_E_CANCE LED
842 && vsaddresults[0] != VSADDRESUL T.ADDRESULT_Success)
843 {
844 ErrorHandler.ThrowOnFailure(addR esult);
845 }
846
847 return dropDataType;
848 }
849 else
850 {
851 if(AddFilesFromProjectReferences(node, f ilesDroppedAsArray))
852 {
853 return dropDataType;
854 }
855 }
856 }
857
858 // If we reached this point then the drop data must be s et to None.
859 // Otherwise the OnPaste will be called with a valid Dro pData and that would actually delete the item.
860 return DropDataType.None;
861 }
862
863 /// <summary>
864 /// Get the dropdatatype from the dataobject
865 /// </summary>
866 /// <param name="pDataObject">The dataobject to be analysed for its format</param>
867 /// <returns>dropdatatype or none if dataobject does not contain known format</returns>
868 internal static DropDataType QueryDropDataType(IOleDataObject pD ataObject)
869 {
870 if(pDataObject == null)
871 {
872 return DropDataType.None;
873 }
874
875 // known formats include File Drops (as from WindowsExpl orer),
876 // VSProject Reference Items and VSProject Storage Items .
877 FORMATETC fmt = DragDropHelper.CreateFormatEtc(NativeMet hods.CF_HDROP);
878
879 if(DragDropHelper.QueryGetData(pDataObject, ref fmt) == VSConstants.S_OK)
880 {
881 return DropDataType.Shell;
882 }
883
884 fmt.cfFormat = DragDropHelper.CF_VSREFPROJECTITEMS;
885 if(DragDropHelper.QueryGetData(pDataObject, ref fmt) == VSConstants.S_OK)
886 {
887 // Data is from a Ref-based project.
888 return DropDataType.VsRef;
889 }
890
891 fmt.cfFormat = DragDropHelper.CF_VSSTGPROJECTITEMS;
892 if(DragDropHelper.QueryGetData(pDataObject, ref fmt) == VSConstants.S_OK)
893 {
894 return DropDataType.VsStg;
895 }
896
897 return DropDataType.None;
898 }
899
900 /// <summary>
901 /// Returns the drop effect.
902 /// </summary>
903 /// <remarks>
904 /// // A directory based project should perform as follow:
905 /// NO MODIFIER
906 /// - COPY if not from current hierarchy,
907 /// - MOVE if from current hierarchy
908 /// SHIFT DRAG - MOVE
909 /// CTRL DRAG - COPY
910 /// CTRL-SHIFT DRAG - NO DROP (used for reference ba sed projects only)
911 /// </remarks>
912 internal DropEffect QueryDropEffect(DropDataType dropDataType, u int grfKeyState)
913 {
914 //Validate the dropdatatype
915 if((dropDataType != DropDataType.Shell) && (dropDataType != DropDataType.VsRef) && (dropDataType != DropDataType.VsStg))
916 {
917 return DropEffect.None;
918 }
919
920 // CTRL-SHIFT
921 if((grfKeyState & NativeMethods.MK_CONTROL) != 0 && (grf KeyState & NativeMethods.MK_SHIFT) != 0)
922 {
923 // Because we are not referenced base, we don't support link
924 return DropEffect.None;
925 }
926
927 // CTRL
928 if((grfKeyState & NativeMethods.MK_CONTROL) != 0)
929 return DropEffect.Copy;
930
931 // SHIFT
932 if((grfKeyState & NativeMethods.MK_SHIFT) != 0)
933 return DropEffect.Move;
934
935 // no modifier
936 if(this.SourceDraggedOrCutOrCopied)
937 {
938 return DropEffect.Move;
939 }
940 else
941 {
942 return DropEffect.Copy;
943 }
944 }
945
946 internal void CleanupSelectionDataObject(bool dropped, bool cut, bool moved)
947 {
948 this.CleanupSelectionDataObject(dropped, cut, moved, fal se);
949 }
950
951 /// <summary>
952 /// After a drop or paste, will use the dwEffects
953 /// to determine whether we need to clean up the source nodes o r not. If
954 /// justCleanup is set, it only does the cleanup work.
955 /// </summary>
956 internal void CleanupSelectionDataObject(bool dropped, bool cut, bool moved, bool justCleanup)
957 {
958 if(this.ItemsDraggedOrCutOrCopied == null || this.ItemsD raggedOrCutOrCopied.Count == 0)
959 {
960 return;
961 }
962
963 try
964 {
965 IVsUIHierarchyWindow w = UIHierarchyUtilities.Ge tUIHierarchyWindow(this.site, HierarchyNode.SolutionExplorer);
966 foreach(HierarchyNode node in this.ItemsDraggedO rCutOrCopied)
967 {
968 if((moved && (cut || dropped) && !justCl eanup))
969 {
970 // do not close it if the doc is dirty or we do not own it
971 bool isDirty, isOpen, isOpenedBy Us;
972 uint docCookie;
973 IVsPersistDocData ppIVsPersistDo cData;
974 DocumentManager manager = node.G etDocumentManager();
975 if(manager != null)
976 {
977 manager.GetDocInfo(out i sOpen, out isDirty, out isOpenedByUs, out docCookie, out ppIVsPersistDocData);
978 if(isDirty || (isOpen && !isOpenedByUs))
979 {
980 continue;
981 }
982
983 // close it if opened
984 if(isOpen)
985 {
986 manager.Close(__ FRAMECLOSE.FRAMECLOSE_NoSave);
987 }
988 }
989
990 node.Remove(true);
991 }
992 else if(w != null)
993 {
994 ErrorHandler.ThrowOnFailure(w.Ex pandItem((IVsUIHierarchy)this, node.ID, EXPANDFLAGS.EXPF_UnCutHighlightItem));
995 }
996 }
997 }
998 finally
999 {
1000 try
1001 {
1002 // Now delete the memory allocated by th e packaging of datasources.
1003 // If we just did a cut, or we are told to cleanup, then we need to free the data object. Otherwise, we leave it
1004 // alone so that you can continue to pas te the data in new locations.
1005 if(moved || cut || justCleanup)
1006 {
1007 this.ItemsDraggedOrCutOrCopied.C lear();
1008 this.CleanAndFlushClipboard();
1009 }
1010 }
1011 finally
1012 {
1013 this.dropDataType = DropDataType.None;
1014 }
1015 }
1016 }
1017
1018 /// <summary>
1019 /// Moves files from one part of our project to another.
1020 /// </summary>
1021 /// <param name="targetNode">the targetHandler node</param>
1022 /// <param name="projectReferences">List of projectref string</p aram>
1023 /// <returns>true if succeeded</returns>
1024 internal bool AddFilesFromProjectReferences(HierarchyNode target Node, string[] projectReferences)
1025 {
1026 //Validate input
1027 if(projectReferences == null)
1028 {
1029 throw new ArgumentException(SR.GetString(SR.Inva lidParameter, CultureInfo.CurrentUICulture), "projectReferences");
1030 }
1031 if(targetNode == null)
1032 {
1033 throw new InvalidOperationException();
1034 }
1035
1036 //Iteratively add files from projectref
1037 foreach(string projectReference in projectReferences)
1038 {
1039 if(projectReference == null)
1040 {
1041 // bad projectref, bail out
1042 return false;
1043 }
1044 if(projectReference.EndsWith("/", StringComparis on.Ordinal) || projectReference.EndsWith("\\", StringComparison.Ordinal))
1045 {
1046 AddFolderFromOtherProject(projectReferen ce, targetNode);
1047 }
1048 else if(!AddFileToNodeFromProjectReference(proje ctReference, targetNode))
1049 {
1050 return false;
1051 }
1052 }
1053
1054 return true;
1055 }
1056
1057 #endregion
1058
1059 #region private helper methods
1060 /// <summary>
1061 /// Empties all the data structures added to the clipboard and f lushes the clipboard.
1062 /// </summary>
1063 private void CleanAndFlushClipboard()
1064 {
1065 IOleDataObject oleDataObject = null;
1066 ErrorHandler.ThrowOnFailure(UnsafeNativeMethods.OleGetCl ipboard(out oleDataObject));
1067 if(oleDataObject == null)
1068 {
1069 return;
1070 }
1071
1072
1073 string sourceProjectPath = DragDropHelper.GetSourceProje ctPath(oleDataObject);
1074
1075 if(!String.IsNullOrEmpty(sourceProjectPath) && NativeMet hods.IsSamePath(sourceProjectPath, this.GetMkDocument()))
1076 {
1077 ErrorHandler.ThrowOnFailure(UnsafeNativeMethods. OleFlushClipboard());
1078 int clipboardOpened = 0;
1079 try
1080 {
1081 ErrorHandler.ThrowOnFailure(clipboardOpe ned = UnsafeNativeMethods.OpenClipboard(IntPtr.Zero));
1082 ErrorHandler.ThrowOnFailure(UnsafeNative Methods.EmptyClipboard());
1083 }
1084 finally
1085 {
1086 if(clipboardOpened == 1)
1087 {
1088 ErrorHandler.ThrowOnFailure(Unsa feNativeMethods.CloseClipboard());
1089 }
1090 }
1091 }
1092 }
1093
1094 private IntPtr PackageSelectionData(StringBuilder sb, bool addEn dFormatDelimiter)
1095 {
1096 if(sb == null || sb.ToString().Length == 0 || this.Items DraggedOrCutOrCopied.Count == 0)
1097 {
1098 return IntPtr.Zero;
1099 }
1100
1101 // Double null at end.
1102 if(addEndFormatDelimiter)
1103 {
1104 if(sb.ToString()[sb.Length - 1] != '\0')
1105 {
1106 sb.Append('\0');
1107 }
1108 }
1109
1110 // We request unmanaged permission to execute the below.
1111 new SecurityPermission(SecurityPermissionFlag.UnmanagedC ode).Demand();
1112
1113 _DROPFILES df = new _DROPFILES();
1114 int dwSize = Marshal.SizeOf(df);
1115 Int16 wideChar = 0;
1116 int dwChar = Marshal.SizeOf(wideChar);
1117 int structSize = dwSize + ((sb.Length + 1) * dwChar);
1118 IntPtr ptr = Marshal.AllocHGlobal(structSize);
1119 df.pFiles = dwSize;
1120 df.fWide = 1;
1121 IntPtr data = IntPtr.Zero;
1122 try
1123 {
1124 data = UnsafeNativeMethods.GlobalLock(ptr);
1125 Marshal.StructureToPtr(df, data, false);
1126 IntPtr strData = new IntPtr((long)data + dwSize) ;
1127 DragDropHelper.CopyStringToHGlobal(sb.ToString() , strData, structSize);
1128 }
1129 finally
1130 {
1131 if(data != IntPtr.Zero)
1132 UnsafeNativeMethods.GlobalUnLock(data);
1133 }
1134
1135 return ptr;
1136 }
1137
1138 #endregion
1139 }
1140 }
OLDNEW
« no previous file with comments | « obsolete/Microsoft.VisualStudio.Project/ProjectNode.cs ('k') | obsolete/Microsoft.VisualStudio.Project/ProjectNode.Events.cs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698