OLD | NEW |
| (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.Diagnostics.CodeAnalysis; | |
8 using System.Globalization; | |
9 using System.IO; | |
10 using System.Runtime.InteropServices; | |
11 using System.Text; | |
12 using Microsoft.VisualStudio; | |
13 using Microsoft.VisualStudio.OLE.Interop; | |
14 using Microsoft.VisualStudio.Shell; | |
15 //#define CCI_TRACING | |
16 using Microsoft.VisualStudio.Shell.Interop; | |
17 using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; | |
18 using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants; | |
19 using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; | |
20 using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; | |
21 | |
22 namespace Microsoft.VisualStudio.Project | |
23 { | |
24 /// <summary> | |
25 /// An object that deals with user interaction via a GUI in the form a h
ierarchy: a parent node with zero or more child nodes, each of which | |
26 /// can itself be a hierarchy. | |
27 /// </summary> | |
28 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainabil
ity", "CA1506:AvoidExcessiveClassCoupling"), CLSCompliant(false), ComVisible(tru
e)] | |
29 public abstract class HierarchyNode : | |
30 IVsUIHierarchy, | |
31 IVsPersistHierarchyItem2, | |
32 Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget, | |
33 IVsHierarchyDropDataSource2, | |
34 IVsHierarchyDropDataSource, | |
35 IVsHierarchyDropDataTarget, | |
36 IVsHierarchyDeleteHandler, | |
37 IDisposable | |
38 //, IVsBuildStatusCallback | |
39 { | |
40 #region nested types | |
41 /// <summary> | |
42 /// DropEffect as defined in oleidl.h | |
43 /// </summary> | |
44 internal enum DropEffect | |
45 { | |
46 None, | |
47 Copy = 1, | |
48 Move = 2, | |
49 Link = 4 | |
50 }; | |
51 #endregion | |
52 | |
53 #region Events | |
54 internal event EventHandler<HierarchyNodeEventArgs> OnChildAdded | |
55 { | |
56 add { onChildAdded += value; } | |
57 remove { onChildAdded -= value; } | |
58 } | |
59 internal event EventHandler<HierarchyNodeEventArgs> OnChildRemov
ed | |
60 { | |
61 add { onChildRemoved += value; } | |
62 remove { onChildRemoved -= value; } | |
63 } | |
64 #endregion | |
65 | |
66 #region static/const fields | |
67 public static readonly Guid SolutionExplorer = new Guid(EnvDTE.C
onstants.vsWindowKindSolutionExplorer); | |
68 public const int NoImage = -1; | |
69 #if DEBUG | |
70 internal static int LastTracedProperty; | |
71 #endif | |
72 #endregion | |
73 | |
74 #region fields | |
75 private EventSinkCollection hierarchyEventSinks = new EventSinkC
ollection(); | |
76 private ProjectNode projectMgr; | |
77 private ProjectElement itemNode; | |
78 private HierarchyNode parentNode; | |
79 private HierarchyNode nextSibling; | |
80 private HierarchyNode firstChild; | |
81 private HierarchyNode lastChild; | |
82 private bool isExpanded; | |
83 private uint hierarchyId; | |
84 private uint docCookie; | |
85 private bool hasDesigner; | |
86 private string virtualNodeName = String.Empty; // Only used by
virtual nodes | |
87 private IVsHierarchy parentHierarchy; | |
88 private int parentHierarchyItemId; | |
89 private NodeProperties nodeProperties; | |
90 private OleServiceProvider oleServiceProvider = new OleServicePr
ovider(); | |
91 private bool excludeNodeFromScc; | |
92 private EventHandler<HierarchyNodeEventArgs> onChildAdded; | |
93 private EventHandler<HierarchyNodeEventArgs> onChildRemoved; | |
94 private bool hasParentNodeNameRelation; | |
95 private List<HierarchyNode> itemsDraggedOrCutOrCopied; | |
96 private bool sourceDraggedOrCutOrCopied; | |
97 | |
98 /// <summary> | |
99 /// Has the object been disposed. | |
100 /// </summary> | |
101 /// <devremark>We will not specify a property for isDisposed, ra
ther it is expected that the a private flag is defined | |
102 /// on all subclasses. We do not want get in a situation where t
he base class's dipose is not called because a child sets the flag through the p
roperty.</devremark> | |
103 private bool isDisposed; | |
104 #endregion | |
105 | |
106 #region abstract properties | |
107 /// <summary> | |
108 /// The URL of the node. | |
109 /// </summary> | |
110 /// <value></value> | |
111 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi
gn", "CA1056:UriPropertiesShouldNotBeStrings")] | |
112 public abstract string Url | |
113 { | |
114 get; | |
115 } | |
116 | |
117 /// <summary> | |
118 /// The Caption of the node. | |
119 /// </summary> | |
120 /// <value></value> | |
121 public abstract string Caption | |
122 { | |
123 get; | |
124 } | |
125 | |
126 /// <summary> | |
127 /// The item type guid associated to a node. | |
128 /// </summary> | |
129 /// <value></value> | |
130 public abstract Guid ItemTypeGuid | |
131 { | |
132 get; | |
133 } | |
134 #endregion | |
135 | |
136 #region virtual properties | |
137 /// <summary> | |
138 /// Defines a string that is used to separate the name relation
from the extension | |
139 /// </summary> | |
140 public virtual string NameRelationSeparator | |
141 { | |
142 get | |
143 { | |
144 return "."; | |
145 } | |
146 } | |
147 | |
148 | |
149 public virtual int MenuCommandId | |
150 { | |
151 get { return VsMenus.IDM_VS_CTXT_NOCOMMANDS; } | |
152 } | |
153 | |
154 | |
155 /// <summary> | |
156 /// Return an imageindex | |
157 /// </summary> | |
158 /// <returns></returns> | |
159 public virtual int ImageIndex | |
160 { | |
161 get { return NoImage; } | |
162 } | |
163 | |
164 /// <summary> | |
165 /// Return an state icon index | |
166 /// </summary> | |
167 /// <returns></returns> | |
168 /// <summary> | |
169 /// Sets the state icon for a file. | |
170 /// </summary> | |
171 public virtual VsStateIcon StateIconIndex | |
172 { | |
173 get | |
174 { | |
175 if(!this.ExcludeNodeFromScc) | |
176 { | |
177 IVsSccManager2 sccManager = this.Project
Mgr.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2; | |
178 | |
179 if(sccManager != null) | |
180 { | |
181 VsStateIcon[] statIcons = new Vs
StateIcon[1] { VsStateIcon.STATEICON_NOSTATEICON }; | |
182 uint[] sccStatus = new uint[1] {
0 }; | |
183 // Get the glyph from the scc ma
nager. Note that it will fail in command line | |
184 // scenarios. | |
185 if(ErrorHandler.Succeeded(sccMan
ager.GetSccGlyph(1, new string[] { this.GetMkDocument() }, statIcons, sccStatus)
)) | |
186 { | |
187 return statIcons[0]; | |
188 } | |
189 } | |
190 } | |
191 | |
192 return VsStateIcon.STATEICON_NOSTATEICON; | |
193 } | |
194 } | |
195 | |
196 /// <summary> | |
197 /// Defines whether a node can execute a command if in selection
. | |
198 /// </summary> | |
199 public virtual bool CanExecuteCommand | |
200 { | |
201 get | |
202 { | |
203 return true; | |
204 } | |
205 } | |
206 | |
207 /// <summary> | |
208 /// Used to determine the sort order of different node types | |
209 /// in the solution explorer window. | |
210 /// Nodes with the same priorities are sorted based on their cap
tions. | |
211 /// </summary> | |
212 public virtual int SortPriority | |
213 { | |
214 get { return DefaultSortOrderNode.HierarchyNode; } | |
215 } | |
216 | |
217 /// <summary> | |
218 /// Defines the properties attached to this node. | |
219 /// </summary> | |
220 public virtual NodeProperties NodeProperties | |
221 { | |
222 get | |
223 { | |
224 if(null == nodeProperties) | |
225 { | |
226 nodeProperties = CreatePropertiesObject(
); | |
227 } | |
228 return this.nodeProperties; | |
229 } | |
230 | |
231 } | |
232 | |
233 /// <summary> | |
234 /// Returns an object that is a special view over this object; t
his is the value | |
235 /// returned by the Object property of the automation objects. | |
236 /// </summary> | |
237 internal virtual object Object | |
238 { | |
239 get { return this; } | |
240 } | |
241 #endregion | |
242 | |
243 #region properties | |
244 | |
245 public OleServiceProvider OleServiceProvider | |
246 { | |
247 get | |
248 { | |
249 return this.oleServiceProvider; | |
250 } | |
251 } | |
252 | |
253 [System.ComponentModel.BrowsableAttribute(false)] | |
254 public ProjectNode ProjectMgr | |
255 { | |
256 get | |
257 { | |
258 return this.projectMgr; | |
259 } | |
260 set | |
261 { | |
262 this.projectMgr = value; | |
263 } | |
264 } | |
265 | |
266 | |
267 [System.ComponentModel.BrowsableAttribute(false)] | |
268 public HierarchyNode NextSibling | |
269 { | |
270 get | |
271 { | |
272 return this.nextSibling; | |
273 } | |
274 set | |
275 { | |
276 this.nextSibling = value; | |
277 } | |
278 } | |
279 | |
280 | |
281 [System.ComponentModel.BrowsableAttribute(false)] | |
282 public HierarchyNode FirstChild | |
283 { | |
284 get | |
285 { | |
286 return this.firstChild; | |
287 } | |
288 set | |
289 { | |
290 this.firstChild = value; | |
291 } | |
292 } | |
293 | |
294 [System.ComponentModel.BrowsableAttribute(false)] | |
295 public HierarchyNode LastChild | |
296 { | |
297 get | |
298 { | |
299 return this.lastChild; | |
300 } | |
301 set | |
302 { | |
303 this.lastChild = value; | |
304 } | |
305 } | |
306 | |
307 | |
308 [System.ComponentModel.BrowsableAttribute(false)] | |
309 public HierarchyNode Parent | |
310 { | |
311 get | |
312 { | |
313 return this.parentNode; | |
314 } | |
315 set | |
316 { | |
317 this.parentNode = value; | |
318 } | |
319 } | |
320 | |
321 | |
322 [System.ComponentModel.BrowsableAttribute(false)] | |
323 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "ID")] | |
324 public uint ID | |
325 { | |
326 get | |
327 { | |
328 return this.hierarchyId; | |
329 } | |
330 internal set | |
331 { | |
332 this.hierarchyId = value; | |
333 } | |
334 } | |
335 | |
336 | |
337 [System.ComponentModel.BrowsableAttribute(false)] | |
338 public ProjectElement ItemNode | |
339 { | |
340 get | |
341 { | |
342 return itemNode; | |
343 } | |
344 set | |
345 { | |
346 itemNode = value; | |
347 } | |
348 } | |
349 | |
350 | |
351 [System.ComponentModel.BrowsableAttribute(false)] | |
352 public bool HasDesigner | |
353 { | |
354 get | |
355 { | |
356 return this.hasDesigner; | |
357 } | |
358 set { this.hasDesigner = value; } | |
359 } | |
360 | |
361 | |
362 [System.ComponentModel.BrowsableAttribute(false)] | |
363 public bool IsExpanded | |
364 { | |
365 get | |
366 { | |
367 return this.isExpanded; | |
368 } | |
369 set { this.isExpanded = value; } | |
370 } | |
371 | |
372 public string VirtualNodeName | |
373 { | |
374 get | |
375 { | |
376 return this.virtualNodeName; | |
377 } | |
378 set | |
379 { | |
380 this.virtualNodeName = value; | |
381 } | |
382 } | |
383 | |
384 | |
385 [System.ComponentModel.BrowsableAttribute(false)] | |
386 public HierarchyNode PreviousSibling | |
387 { | |
388 get | |
389 { | |
390 if(this.parentNode == null) return null; | |
391 HierarchyNode prev = null; | |
392 for(HierarchyNode child = this.parentNode.firstC
hild; child != null; child = child.nextSibling) | |
393 { | |
394 if(child == this) | |
395 break; | |
396 prev = child; | |
397 } | |
398 return prev; | |
399 } | |
400 } | |
401 | |
402 public uint DocCookie | |
403 { | |
404 get | |
405 { | |
406 return this.docCookie; | |
407 } | |
408 set | |
409 { | |
410 this.docCookie = value; | |
411 } | |
412 } | |
413 | |
414 /// <summary> | |
415 /// Specifies if a Node is under source control. | |
416 /// </summary> | |
417 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Scc")] | |
418 public bool ExcludeNodeFromScc | |
419 { | |
420 get | |
421 { | |
422 return this.excludeNodeFromScc; | |
423 } | |
424 set | |
425 { | |
426 this.excludeNodeFromScc = value; | |
427 } | |
428 } | |
429 | |
430 /// <summary> | |
431 /// Defines if a node a name relation to its parent node | |
432 /// | |
433 /// </summary> | |
434 public bool HasParentNodeNameRelation | |
435 { | |
436 get | |
437 { | |
438 return this.hasParentNodeNameRelation; | |
439 } | |
440 set | |
441 { | |
442 this.hasParentNodeNameRelation = value; | |
443 } | |
444 } | |
445 | |
446 protected bool SourceDraggedOrCutOrCopied | |
447 { | |
448 get | |
449 { | |
450 return this.sourceDraggedOrCutOrCopied; | |
451 } | |
452 set | |
453 { | |
454 this.sourceDraggedOrCutOrCopied = value; | |
455 } | |
456 } | |
457 | |
458 protected IList<HierarchyNode> ItemsDraggedOrCutOrCopied | |
459 { | |
460 get | |
461 { | |
462 return this.itemsDraggedOrCutOrCopied; | |
463 } | |
464 } | |
465 #endregion | |
466 | |
467 #region ctors | |
468 | |
469 protected HierarchyNode() | |
470 { | |
471 this.IsExpanded = true; | |
472 } | |
473 | |
474 protected HierarchyNode(ProjectNode root, ProjectElement element
) | |
475 { | |
476 this.projectMgr = root; | |
477 this.itemNode = element; | |
478 this.hierarchyId = this.projectMgr.ItemIdMap.Add(this); | |
479 this.oleServiceProvider.AddService(typeof(IVsHierarchy),
root, false); | |
480 } | |
481 | |
482 /// <summary> | |
483 /// Overloaded ctor. | |
484 /// </summary> | |
485 /// <param name="root"></param> | |
486 protected HierarchyNode(ProjectNode root) | |
487 { | |
488 this.projectMgr = root; | |
489 this.itemNode = new ProjectElement(this.projectMgr, null
, true); | |
490 this.hierarchyId = this.projectMgr.ItemIdMap.Add(this); | |
491 this.oleServiceProvider.AddService(typeof(IVsHierarchy),
root, false); | |
492 } | |
493 #endregion | |
494 | |
495 #region static methods | |
496 /// <summary> | |
497 /// Get the outer IVsHierarchy implementation. | |
498 /// This is used for scenario where a flavor may be modifying th
e behavior | |
499 /// </summary> | |
500 internal static IVsHierarchy GetOuterHierarchy(HierarchyNode nod
e) | |
501 { | |
502 IVsHierarchy hierarchy = null; | |
503 // The hierarchy of a node is its project node hierarchy | |
504 IntPtr projectUnknown = Marshal.GetIUnknownForObject(nod
e.projectMgr); | |
505 try | |
506 { | |
507 hierarchy = (IVsHierarchy)Marshal.GetTypedObject
ForIUnknown(projectUnknown, typeof(IVsHierarchy)); | |
508 } | |
509 finally | |
510 { | |
511 if(projectUnknown != IntPtr.Zero) | |
512 { | |
513 Marshal.Release(projectUnknown); | |
514 } | |
515 } | |
516 return hierarchy; | |
517 } | |
518 #endregion | |
519 | |
520 #region virtual methods | |
521 /// <summary> | |
522 /// Creates an object derived from NodeProperties that will be u
sed to expose properties | |
523 /// spacific for this object to the property browser. | |
524 /// </summary> | |
525 /// <returns></returns> | |
526 protected virtual NodeProperties CreatePropertiesObject() | |
527 { | |
528 return null; | |
529 } | |
530 | |
531 /// <summary> | |
532 /// Return an iconhandle | |
533 /// </summary> | |
534 /// <param name="open"></param> | |
535 /// <returns></returns> | |
536 public virtual object GetIconHandle(bool open) | |
537 { | |
538 return null; | |
539 } | |
540 | |
541 /// <summary> | |
542 /// AddChild - add a node, sorted in the right location. | |
543 /// </summary> | |
544 /// <param name="node">The node to add.</param> | |
545 public virtual void AddChild(HierarchyNode node) | |
546 { | |
547 if(node == null) | |
548 { | |
549 throw new ArgumentNullException("node"); | |
550 } | |
551 | |
552 // make sure the node is in the map. | |
553 Object nodeWithSameID = this.projectMgr.ItemIdMap[node.h
ierarchyId]; | |
554 if(!Object.ReferenceEquals(node, nodeWithSameID as Hiera
rchyNode)) | |
555 { | |
556 if(nodeWithSameID == null && node.ID <= this.Pro
jectMgr.ItemIdMap.Count) | |
557 { // reuse our hierarchy id if possible. | |
558 this.projectMgr.ItemIdMap.SetAt(node.hie
rarchyId, this); | |
559 } | |
560 else | |
561 { | |
562 throw new InvalidOperationException(); | |
563 } | |
564 } | |
565 | |
566 HierarchyNode previous = null; | |
567 for(HierarchyNode n = this.firstChild; n != null; n = n.
nextSibling) | |
568 { | |
569 if(this.ProjectMgr.CompareNodes(node, n) > 0) br
eak; | |
570 previous = n; | |
571 } | |
572 // insert "node" after "previous". | |
573 if(previous != null) | |
574 { | |
575 node.nextSibling = previous.nextSibling; | |
576 previous.nextSibling = node; | |
577 if(previous == this.lastChild) | |
578 { | |
579 this.lastChild = node; | |
580 } | |
581 } | |
582 else | |
583 { | |
584 if(this.lastChild == null) | |
585 { | |
586 this.lastChild = node; | |
587 } | |
588 node.nextSibling = this.firstChild; | |
589 this.firstChild = node; | |
590 } | |
591 node.parentNode = this; | |
592 this.OnItemAdded(this, node); | |
593 } | |
594 | |
595 /// <summary> | |
596 /// Removes a node from the hierarchy. | |
597 /// </summary> | |
598 /// <param name="node">The node to remove.</param> | |
599 public virtual void RemoveChild(HierarchyNode node) | |
600 { | |
601 if(node == null) | |
602 { | |
603 throw new ArgumentNullException("node"); | |
604 } | |
605 | |
606 this.projectMgr.ItemIdMap.Remove(node); | |
607 | |
608 HierarchyNode last = null; | |
609 for(HierarchyNode n = this.firstChild; n != null; n = n.
nextSibling) | |
610 { | |
611 if(n == node) | |
612 { | |
613 if(last != null) | |
614 { | |
615 last.nextSibling = n.nextSibling
; | |
616 } | |
617 if(n == this.lastChild) | |
618 { | |
619 if(last == this.lastChild) | |
620 { | |
621 this.lastChild = null; | |
622 } | |
623 else | |
624 { | |
625 this.lastChild = last; | |
626 } | |
627 } | |
628 if(n == this.firstChild) | |
629 { | |
630 this.firstChild = n.nextSibling; | |
631 } | |
632 return; | |
633 } | |
634 last = n; | |
635 } | |
636 throw new InvalidOperationException("Node not found"); | |
637 } | |
638 | |
639 /// <summary> | |
640 /// Returns an automation object representing this node | |
641 /// </summary> | |
642 /// <returns>The automation object</returns> | |
643 public virtual object GetAutomationObject() | |
644 { | |
645 return new Automation.OAProjectItem<HierarchyNode>(this.
projectMgr.GetAutomationObject() as Automation.OAProject, this); | |
646 } | |
647 | |
648 /// <summary> | |
649 /// Returns a property object based on a property id | |
650 /// </summary> | |
651 /// <param name="propId">the property id of the property request
ed</param> | |
652 /// <returns>the property object requested</returns> | |
653 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Perf
ormance", "CA1800:DoNotCastUnnecessarily"), System.Diagnostics.CodeAnalysis.Supp
ressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] | |
654 public virtual object GetProperty(int propId) | |
655 { | |
656 object result = null; | |
657 switch((__VSHPROPID)propId) | |
658 { | |
659 case __VSHPROPID.VSHPROPID_Expandable: | |
660 result = (this.firstChild != null); | |
661 break; | |
662 | |
663 case __VSHPROPID.VSHPROPID_Caption: | |
664 result = this.Caption; | |
665 break; | |
666 | |
667 case __VSHPROPID.VSHPROPID_Name: | |
668 result = this.Caption; | |
669 break; | |
670 | |
671 case __VSHPROPID.VSHPROPID_ExpandByDefault: | |
672 result = false; | |
673 break; | |
674 | |
675 case __VSHPROPID.VSHPROPID_IconImgList: | |
676 result = this.ProjectMgr.ImageHandler.Im
ageList.Handle; | |
677 break; | |
678 | |
679 case __VSHPROPID.VSHPROPID_OpenFolderIconIndex: | |
680 case __VSHPROPID.VSHPROPID_IconIndex: | |
681 int index = this.ImageIndex; | |
682 if(index != NoImage) | |
683 { | |
684 result = index; | |
685 } | |
686 break; | |
687 | |
688 case __VSHPROPID.VSHPROPID_StateIconIndex: | |
689 result = (int)this.StateIconIndex; | |
690 break; | |
691 | |
692 case __VSHPROPID.VSHPROPID_IconHandle: | |
693 result = GetIconHandle(false); | |
694 break; | |
695 | |
696 case __VSHPROPID.VSHPROPID_OpenFolderIconHandle: | |
697 result = GetIconHandle(true); | |
698 break; | |
699 | |
700 case __VSHPROPID.VSHPROPID_NextVisibleSibling: | |
701 goto case __VSHPROPID.VSHPROPID_NextSibl
ing; | |
702 | |
703 case __VSHPROPID.VSHPROPID_NextSibling: | |
704 result = (int)((this.nextSibling != null
) ? this.nextSibling.hierarchyId : VSConstants.VSITEMID_NIL); | |
705 break; | |
706 | |
707 case __VSHPROPID.VSHPROPID_FirstChild: | |
708 goto case __VSHPROPID.VSHPROPID_FirstVis
ibleChild; | |
709 | |
710 case __VSHPROPID.VSHPROPID_FirstVisibleChild: | |
711 result = (int)((this.firstChild != null)
? this.firstChild.hierarchyId : VSConstants.VSITEMID_NIL); | |
712 break; | |
713 | |
714 case __VSHPROPID.VSHPROPID_Parent: | |
715 if(null == this.parentNode) | |
716 { | |
717 unchecked { result = new IntPtr(
(int)VSConstants.VSITEMID_NIL); } | |
718 } | |
719 else | |
720 { | |
721 result = new IntPtr((int)this.pa
rentNode.hierarchyId); // see bug 176470 | |
722 } | |
723 break; | |
724 | |
725 case __VSHPROPID.VSHPROPID_ParentHierarchyItemid
: | |
726 if(parentHierarchy != null) | |
727 { | |
728 result = (IntPtr)parentHierarchy
ItemId; // VS requires VT_I4 | VT_INT_PTR | |
729 } | |
730 break; | |
731 | |
732 case __VSHPROPID.VSHPROPID_ParentHierarchy: | |
733 result = parentHierarchy; | |
734 break; | |
735 | |
736 case __VSHPROPID.VSHPROPID_Root: | |
737 result = Marshal.GetIUnknownForObject(th
is.projectMgr); | |
738 break; | |
739 | |
740 case __VSHPROPID.VSHPROPID_Expanded: | |
741 result = this.isExpanded; | |
742 break; | |
743 | |
744 case __VSHPROPID.VSHPROPID_BrowseObject: | |
745 result = this.NodeProperties; | |
746 if(result != null) result = new Dispatch
Wrapper(result); | |
747 break; | |
748 | |
749 case __VSHPROPID.VSHPROPID_EditLabel: | |
750 if(this.ProjectMgr != null && !this.Proj
ectMgr.IsClosed && !this.ProjectMgr.IsCurrentStateASuppressCommandsMode()) | |
751 { | |
752 result = GetEditLabel(); | |
753 } | |
754 break; | |
755 | |
756 case __VSHPROPID.VSHPROPID_SaveName: | |
757 //SaveName is the name shown in the Save
and the Save Changes dialog boxes. | |
758 result = this.Caption; | |
759 break; | |
760 | |
761 case __VSHPROPID.VSHPROPID_ItemDocCookie: | |
762 if(this.docCookie != 0) return (IntPtr)t
his.docCookie; //cast to IntPtr as some callers expect VT_INT | |
763 break; | |
764 | |
765 case __VSHPROPID.VSHPROPID_ExtObject: | |
766 result = GetAutomationObject(); | |
767 break; | |
768 } | |
769 | |
770 __VSHPROPID2 id2 = (__VSHPROPID2)propId; | |
771 switch(id2) | |
772 { | |
773 case __VSHPROPID2.VSHPROPID_NoDefaultNestedHierS
orting: | |
774 return true; // We are doing the sorting
ourselves through VSHPROPID_FirstChild and VSHPROPID_NextSibling | |
775 case __VSHPROPID2.VSHPROPID_BrowseObjectCATID: | |
776 { | |
777 // If there is a browse object a
nd it is a NodeProperties, then get it's CATID | |
778 object browseObject = this.GetPr
operty((int)__VSHPROPID.VSHPROPID_BrowseObject); | |
779 if(browseObject != null) | |
780 { | |
781 if(browseObject is Dispa
tchWrapper) | |
782 browseObject = (
(DispatchWrapper)browseObject).WrappedObject; | |
783 result = this.ProjectMgr
.GetCATIDForType(browseObject.GetType()).ToString("B"); | |
784 if(String.CompareOrdinal
(result as string, Guid.Empty.ToString("B")) == 0) | |
785 result = null; | |
786 } | |
787 break; | |
788 } | |
789 case __VSHPROPID2.VSHPROPID_ExtObjectCATID: | |
790 { | |
791 // If there is a extensibility o
bject and it is a NodeProperties, then get it's CATID | |
792 object extObject = this.GetPrope
rty((int)__VSHPROPID.VSHPROPID_ExtObject); | |
793 if(extObject != null) | |
794 { | |
795 if(extObject is Dispatch
Wrapper) | |
796 extObject = ((Di
spatchWrapper)extObject).WrappedObject; | |
797 result = this.ProjectMgr
.GetCATIDForType(extObject.GetType()).ToString("B"); | |
798 if(String.CompareOrdinal
(result as string, Guid.Empty.ToString("B")) == 0) | |
799 result = null; | |
800 } | |
801 break; | |
802 } | |
803 } | |
804 #if DEBUG | |
805 if(propId != LastTracedProperty) | |
806 { | |
807 string trailer = (result == null) ? "null" : res
ult.ToString(); | |
808 CCITracing.TraceCall(this.hierarchyId + "," + pr
opId.ToString() + " = " + trailer); | |
809 LastTracedProperty = propId; // some basic filte
ring here... | |
810 } | |
811 #endif | |
812 return result; | |
813 } | |
814 | |
815 /// <summary> | |
816 /// Sets the value of a property for a given property id | |
817 /// </summary> | |
818 /// <param name="propid">the property id of the property to be s
et</param> | |
819 /// <param name="value">value of the property</param> | |
820 /// <returns>S_OK if succeeded</returns> | |
821 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "propid")] | |
822 public virtual int SetProperty(int propid, object value) | |
823 { | |
824 __VSHPROPID id = (__VSHPROPID)propid; | |
825 | |
826 CCITracing.TraceCall(this.hierarchyId + "," + id.ToStrin
g()); | |
827 switch(id) | |
828 { | |
829 case __VSHPROPID.VSHPROPID_Expanded: | |
830 this.isExpanded = (bool)value; | |
831 break; | |
832 | |
833 case __VSHPROPID.VSHPROPID_ParentHierarchy: | |
834 parentHierarchy = (IVsHierarchy)value; | |
835 break; | |
836 | |
837 case __VSHPROPID.VSHPROPID_ParentHierarchyItemid
: | |
838 parentHierarchyItemId = (int)value; | |
839 break; | |
840 | |
841 case __VSHPROPID.VSHPROPID_EditLabel: | |
842 return SetEditLabel((string)value); | |
843 | |
844 default: | |
845 CCITracing.TraceCall(" unhandled"); | |
846 break; | |
847 } | |
848 return VSConstants.S_OK; | |
849 } | |
850 | |
851 /// <summary> | |
852 /// Get a guid property | |
853 /// </summary> | |
854 /// <param name="propid">property id for the guid property reque
sted</param> | |
855 /// <param name="guid">the requested guid</param> | |
856 /// <returns>S_OK if succeded</returns> | |
857 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "propid")] | |
858 public virtual int GetGuidProperty(int propid, out Guid guid) | |
859 { | |
860 guid = Guid.Empty; | |
861 if(propid == (int)__VSHPROPID.VSHPROPID_TypeGuid) | |
862 { | |
863 guid = this.ItemTypeGuid; | |
864 } | |
865 | |
866 if(guid.CompareTo(Guid.Empty) == 0) | |
867 { | |
868 return VSConstants.DISP_E_MEMBERNOTFOUND; | |
869 } | |
870 | |
871 return VSConstants.S_OK; | |
872 } | |
873 | |
874 /// <summary> | |
875 /// Set a guid property. | |
876 /// </summary> | |
877 /// <param name="propid">property id of the guid property to be
set</param> | |
878 /// <param name="guid">the guid to be set</param> | |
879 /// <returns>E_NOTIMPL</returns> | |
880 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "propid")] | |
881 public virtual int SetGuidProperty(int propid, ref Guid guid) | |
882 { | |
883 return VSConstants.E_NOTIMPL; | |
884 } | |
885 | |
886 /// <summary> | |
887 /// Called by the shell when a node has been renamed from the GU
I | |
888 /// </summary> | |
889 /// <param name="label"></param> | |
890 /// <returns>E_NOTIMPL</returns> | |
891 public virtual int SetEditLabel(string label) | |
892 { | |
893 return VSConstants.E_NOTIMPL; | |
894 } | |
895 | |
896 /// <summary> | |
897 /// Called by the shell to get the node caption when the user tr
ies to rename from the GUI | |
898 /// </summary> | |
899 /// <returns>the node cation</returns> | |
900 public virtual string GetEditLabel() | |
901 { | |
902 return this.Caption; | |
903 } | |
904 | |
905 /// <summary> | |
906 /// This method is called by the interface method GetMkDocument
to specify the item moniker. | |
907 /// </summary> | |
908 /// <returns>The moniker for this item</returns> | |
909 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "Mk")] | |
910 public virtual string GetMkDocument() | |
911 { | |
912 return String.Empty; | |
913 } | |
914 | |
915 /// <summary> | |
916 /// Removes items from the hierarchy. Project overwrites this | |
917 /// </summary> | |
918 /// <param name="removeFromStorage"></param> | |
919 public virtual void Remove(bool removeFromStorage) | |
920 { | |
921 string documentToRemove = this.GetMkDocument(); | |
922 | |
923 // Ask Document tracker listeners if we can remove the i
tem. | |
924 string[] filesToBeDeleted = new string[1] { documentToRe
move }; | |
925 VSQUERYREMOVEFILEFLAGS[] queryRemoveFlags = this.GetQuer
yRemoveFileFlags(filesToBeDeleted); | |
926 if(!this.ProjectMgr.Tracker.CanRemoveItems(filesToBeDele
ted, queryRemoveFlags)) | |
927 { | |
928 return; | |
929 } | |
930 | |
931 // Close the document if it has a manager. | |
932 DocumentManager manager = this.GetDocumentManager(); | |
933 if(manager != null) | |
934 { | |
935 if(manager.Close(!removeFromStorage ? __FRAMECLO
SE.FRAMECLOSE_PromptSave : __FRAMECLOSE.FRAMECLOSE_NoSave) == VSConstants.E_ABOR
T) | |
936 { | |
937 // User cancelled operation in message b
ox. | |
938 return; | |
939 } | |
940 } | |
941 | |
942 // Check out the project file. | |
943 if(!this.ProjectMgr.QueryEditProjectFile(false)) | |
944 { | |
945 throw Marshal.GetExceptionForHR(VSConstants.OLE_
E_PROMPTSAVECANCELLED); | |
946 } | |
947 | |
948 // Notify hierarchy event listeners that the file is goi
ng to be removed. | |
949 OnItemDeleted(); | |
950 | |
951 // Remove child if any before removing from the hierarch
y | |
952 for(HierarchyNode child = this.FirstChild; child != null
; child = child.NextSibling) | |
953 { | |
954 child.Remove(removeFromStorage); | |
955 } | |
956 | |
957 // the project node has no parentNode | |
958 if(this.parentNode != null) | |
959 { | |
960 // Remove from the Hierarchy | |
961 this.parentNode.RemoveChild(this); | |
962 } | |
963 | |
964 // We save here the path to delete since this.Url might
call the Include which will be deleted by the RemoveFromProjectFile call. | |
965 string pathToDelete = this.GetMkDocument(); | |
966 this.itemNode.RemoveFromProjectFile(); | |
967 | |
968 if(removeFromStorage) | |
969 { | |
970 this.DeleteFromStorage(pathToDelete); | |
971 } | |
972 | |
973 // Close the document window if opened. | |
974 CloseDocumentWindow(this); | |
975 | |
976 // Notify document tracker listeners that we have remove
d the item. | |
977 VSREMOVEFILEFLAGS[] removeFlags = this.GetRemoveFileFlag
s(filesToBeDeleted); | |
978 Debug.Assert(removeFlags != null, "At least an empty arr
ay should be returned for the GetRemoveFileFlags"); | |
979 this.ProjectMgr.Tracker.OnItemRemoved(documentToRemove,
removeFlags[0]); | |
980 | |
981 // Notify hierarchy event listeners that we have removed
the item | |
982 if(null != this.parentNode.onChildRemoved) | |
983 { | |
984 HierarchyNodeEventArgs args = new HierarchyNodeE
ventArgs(this); | |
985 parentNode.onChildRemoved(parentNode, args); | |
986 } | |
987 | |
988 // Notify hierarchy event listeners that items have been
invalidated | |
989 OnInvalidateItems(this.parentNode); | |
990 | |
991 // Dispose the node now that is deleted. | |
992 this.Dispose(true); | |
993 } | |
994 | |
995 /// <summary> | |
996 /// Returns the relational name which is defined as the first pa
rt of the caption until indexof NameRelationSeparator | |
997 /// </summary> | |
998 public virtual string GetRelationalName() | |
999 { | |
1000 //Get the first part of the caption | |
1001 string[] partsOfParent = this.Caption.Split(new string[]
{ this.NameRelationSeparator }, StringSplitOptions.None); | |
1002 return partsOfParent[0]; | |
1003 } | |
1004 | |
1005 /// <summary> | |
1006 /// Returns the 'extension' of the relational name | |
1007 /// e.g. form1.resx returns .resx, form1.designer.cs returns .de
signer.cs | |
1008 /// </summary> | |
1009 /// <returns>The extension</returns> | |
1010 public virtual string GetRelationNameExtension() | |
1011 { | |
1012 return this.Caption.Substring(this.Caption.IndexOf(this.
NameRelationSeparator, StringComparison.Ordinal)); | |
1013 } | |
1014 | |
1015 /// <summary> | |
1016 /// Close open document frame for a specific node. | |
1017 /// </summary> | |
1018 protected void CloseDocumentWindow(HierarchyNode node) | |
1019 { | |
1020 // We walk the RDT looking for all running documents att
ached to this hierarchy and itemid. There | |
1021 // are cases where there may be two different editors (n
ot views) open on the same document. | |
1022 IEnumRunningDocuments pEnumRdt; | |
1023 IVsRunningDocumentTable pRdt = this.GetService(typeof(SV
sRunningDocumentTable)) as IVsRunningDocumentTable; | |
1024 if(pRdt == null) | |
1025 { | |
1026 throw new InvalidOperationException(); | |
1027 } | |
1028 if(ErrorHandler.Succeeded(pRdt.GetRunningDocumentsEnum(o
ut pEnumRdt))) | |
1029 { | |
1030 uint[] cookie = new uint[1]; | |
1031 uint fetched; | |
1032 uint saveOptions = (uint)__VSSLNSAVEOPTIONS.SLNS
AVEOPT_NoSave; | |
1033 IVsHierarchy srpOurHier = node.projectMgr as IVs
Hierarchy; | |
1034 | |
1035 ErrorHandler.ThrowOnFailure(pEnumRdt.Reset()); | |
1036 while(VSConstants.S_OK == pEnumRdt.Next(1, cooki
e, out fetched)) | |
1037 { | |
1038 // Note we can pass NULL for all paramet
ers we don't care about | |
1039 uint empty; | |
1040 string emptyStr; | |
1041 IntPtr ppunkDocData; | |
1042 IVsHierarchy srpHier; | |
1043 uint itemid = VSConstants.VSITEMID_NIL; | |
1044 | |
1045 ErrorHandler.ThrowOnFailure(pRdt.GetDocu
mentInfo( | |
1046
cookie[0], | |
1047
out empty, | |
1048
out empty, | |
1049
out empty, | |
1050
out emptyStr, | |
1051
out srpHier, | |
1052
out itemid, | |
1053
out ppunkDocData)); | |
1054 | |
1055 // Is this one of our documents? | |
1056 if(Utilities.IsSameComObject(srpOurHier,
srpHier) && itemid == node.ID) | |
1057 { | |
1058 IVsSolution soln = GetService(ty
peof(SVsSolution)) as IVsSolution; | |
1059 ErrorHandler.ThrowOnFailure(soln
.CloseSolutionElement(saveOptions, srpOurHier, cookie[0])); | |
1060 } | |
1061 if(ppunkDocData != IntPtr.Zero) | |
1062 Marshal.Release(ppunkDocData); | |
1063 | |
1064 } | |
1065 } | |
1066 } | |
1067 | |
1068 /// <summary> | |
1069 /// Redraws the state icon if the node is not excluded from sour
ce control. | |
1070 /// </summary> | |
1071 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Scc")] | |
1072 protected internal virtual void UpdateSccStateIcons() | |
1073 { | |
1074 if(!this.ExcludeNodeFromScc) | |
1075 { | |
1076 this.ReDraw(UIHierarchyElement.SccState); | |
1077 } | |
1078 } | |
1079 | |
1080 /// <summary> | |
1081 /// To be overwritten by descendants. | |
1082 /// </summary> | |
1083 protected internal virtual int SetEditLabel(string label, string
relativePath) | |
1084 { | |
1085 throw new NotImplementedException(); | |
1086 } | |
1087 | |
1088 /// <summary> | |
1089 /// Called by the drag and drop implementation to ask the node | |
1090 /// which is being dragged/droped over which nodes should | |
1091 /// process the operation. | |
1092 /// This allows for dragging to a node that cannot contain | |
1093 /// items to let its parent accept the drop | |
1094 /// </summary> | |
1095 /// <returns>HierarchyNode that accept the drop handling</return
s> | |
1096 protected internal virtual HierarchyNode GetDragTargetHandlerNod
e() | |
1097 { | |
1098 return this; | |
1099 } | |
1100 | |
1101 /// <summary> | |
1102 /// Add a new Folder to the project hierarchy. | |
1103 /// </summary> | |
1104 /// <returns>S_OK if succeeded, otherwise an error</returns> | |
1105 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Perf
ormance", "CA1800:DoNotCastUnnecessarily")] | |
1106 protected virtual int AddNewFolder() | |
1107 { | |
1108 // Check out the project file. | |
1109 if(!this.ProjectMgr.QueryEditProjectFile(false)) | |
1110 { | |
1111 throw Marshal.GetExceptionForHR(VSConstants.OLE_
E_PROMPTSAVECANCELLED); | |
1112 } | |
1113 | |
1114 try | |
1115 { | |
1116 // Generate a new folder name | |
1117 string newFolderName; | |
1118 ErrorHandler.ThrowOnFailure(this.projectMgr.Gene
rateUniqueItemName(this.hierarchyId, String.Empty, String.Empty, out newFolderNa
me)); | |
1119 | |
1120 // create the project part of it, the project fi
le | |
1121 HierarchyNode child = this.ProjectMgr.CreateFold
erNodes(Path.Combine(this.virtualNodeName, newFolderName)); | |
1122 | |
1123 if(child is FolderNode) | |
1124 { | |
1125 ((FolderNode)child).CreateDirectory(); | |
1126 } | |
1127 | |
1128 // If we are in automation mode then skip the ui
part which is about renaming the folder | |
1129 if(!Utilities.IsInAutomationFunction(this.projec
tMgr.Site)) | |
1130 { | |
1131 IVsUIHierarchyWindow uiWindow = UIHierar
chyUtilities.GetUIHierarchyWindow(this.projectMgr.Site, SolutionExplorer); | |
1132 // we need to get into label edit mode n
ow... | |
1133 // so first select the new guy... | |
1134 ErrorHandler.ThrowOnFailure(uiWindow.Exp
andItem(this.projectMgr, child.hierarchyId, EXPANDFLAGS.EXPF_SelectItem)); | |
1135 // them post the rename command to the s
hell. Folder verification and creation will | |
1136 // happen in the setlabel code... | |
1137 IVsUIShell shell = this.projectMgr.Site.
GetService(typeof(SVsUIShell)) as IVsUIShell; | |
1138 | |
1139 Debug.Assert(shell != null, "Could not g
et the ui shell from the project"); | |
1140 if(shell == null) | |
1141 { | |
1142 return VSConstants.E_FAIL; | |
1143 } | |
1144 | |
1145 object dummy = null; | |
1146 Guid cmdGroup = VsMenus.guidStandardComm
andSet97; | |
1147 ErrorHandler.ThrowOnFailure(shell.PostEx
ecCommand(ref cmdGroup, (uint)VsCommands.Rename, 0, ref dummy)); | |
1148 } | |
1149 } | |
1150 catch(COMException e) | |
1151 { | |
1152 Trace.WriteLine("Exception : " + e.Message); | |
1153 return e.ErrorCode; | |
1154 } | |
1155 | |
1156 return VSConstants.S_OK; | |
1157 } | |
1158 | |
1159 protected virtual int AddItemToHierarchy(HierarchyAddType addTyp
e) | |
1160 { | |
1161 CCITracing.TraceCall(); | |
1162 IVsAddProjectItemDlg addItemDialog; | |
1163 | |
1164 string strFilter = String.Empty; | |
1165 int iDontShowAgain; | |
1166 uint uiFlags; | |
1167 IVsProject3 project = (IVsProject3)this.projectMgr; | |
1168 | |
1169 string strBrowseLocations = Path.GetDirectoryName(this.p
rojectMgr.BaseURI.Uri.LocalPath); | |
1170 | |
1171 System.Guid projectGuid = this.projectMgr.ProjectGuid; | |
1172 | |
1173 addItemDialog = this.GetService(typeof(IVsAddProjectItem
Dlg)) as IVsAddProjectItemDlg; | |
1174 | |
1175 if(addType == HierarchyAddType.AddNewItem) | |
1176 uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddN
ewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSAD
DITEM_AllowHiddenTreeView); | |
1177 else | |
1178 uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddE
xistingItems | __VSADDITEMFLAGS.VSADDITEM_AllowMultiSelect | __VSADDITEMFLAGS.VS
ADDITEM_AllowStickyFilter); | |
1179 | |
1180 ErrorHandler.ThrowOnFailure(addItemDialog.AddProjectItem
Dlg(this.hierarchyId, ref projectGuid, project, uiFlags, null, null, ref strBrow
seLocations, ref strFilter, out iDontShowAgain)); /*&fDontShowAgain*/ | |
1181 | |
1182 return VSConstants.S_OK; | |
1183 } | |
1184 | |
1185 /// <summary> | |
1186 /// Overwritten in subclasses | |
1187 /// </summary> | |
1188 protected virtual void DoDefaultAction() | |
1189 { | |
1190 CCITracing.TraceCall(); | |
1191 } | |
1192 | |
1193 /// <summary> | |
1194 /// Handles the exclude from project command. | |
1195 /// </summary> | |
1196 /// <returns></returns> | |
1197 protected virtual int ExcludeFromProject() | |
1198 { | |
1199 Debug.Assert(this.ProjectMgr != null, "The project item
" + this.ToString() + " has not been initialised correctly. It has a null Projec
tMgr"); | |
1200 this.Remove(false); | |
1201 return VSConstants.S_OK; | |
1202 } | |
1203 | |
1204 /// <summary> | |
1205 /// Handles the Show in Designer command. | |
1206 /// </summary> | |
1207 /// <returns></returns> | |
1208 protected virtual int ShowInDesigner(IList<HierarchyNode> select
edNodes) | |
1209 { | |
1210 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1211 } | |
1212 | |
1213 /// <summary> | |
1214 /// Prepares a selected node for clipboard. | |
1215 /// It takes the the project reference string of this item and a
dds it to a stringbuilder. | |
1216 /// </summary> | |
1217 /// <returns>A stringbuilder.</returns> | |
1218 /// <devremark>This method has to be public since seleceted node
s will call it.</devremark> | |
1219 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShould
BeCasedCorrectly", MessageId = "ClipBoard")] | |
1220 protected internal virtual StringBuilder PrepareSelectedNodesFor
ClipBoard() | |
1221 { | |
1222 Debug.Assert(this.ProjectMgr != null, " No project manan
ager available for this node " + ToString()); | |
1223 Debug.Assert(this.ProjectMgr.ItemsDraggedOrCutOrCopied !
= null, " The itemsdragged list should have been initialized prior calling this
method"); | |
1224 StringBuilder sb = new StringBuilder(); | |
1225 | |
1226 if(this.hierarchyId == VSConstants.VSITEMID_ROOT) | |
1227 { | |
1228 if(this.ProjectMgr.ItemsDraggedOrCutOrCopied !=
null) | |
1229 { | |
1230 this.ProjectMgr.ItemsDraggedOrCutOrCopie
d.Clear();// abort | |
1231 } | |
1232 return sb; | |
1233 } | |
1234 | |
1235 if(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null) | |
1236 { | |
1237 this.ProjectMgr.ItemsDraggedOrCutOrCopied.Add(th
is); | |
1238 } | |
1239 | |
1240 string projref = String.Empty; | |
1241 IVsSolution solution = this.GetService(typeof(IVsSolutio
n)) as IVsSolution; | |
1242 if(solution != null) | |
1243 { | |
1244 ErrorHandler.ThrowOnFailure(solution.GetProjrefO
fItem(this.ProjectMgr, this.hierarchyId, out projref)); | |
1245 if(String.IsNullOrEmpty(projref)) | |
1246 { | |
1247 if(this.ProjectMgr.ItemsDraggedOrCutOrCo
pied != null) | |
1248 { | |
1249 this.ProjectMgr.ItemsDraggedOrCu
tOrCopied.Clear();// abort | |
1250 } | |
1251 return sb; | |
1252 } | |
1253 } | |
1254 | |
1255 // Append the projectref and a null terminator to the st
ring builder | |
1256 sb.Append(projref); | |
1257 sb.Append('\0'); | |
1258 | |
1259 return sb; | |
1260 } | |
1261 | |
1262 /// <summary> | |
1263 /// Returns the Cannonical Name | |
1264 /// </summary> | |
1265 /// <returns>Cannonical Name</returns> | |
1266 protected virtual string GetCanonicalName() | |
1267 { | |
1268 return this.GetMkDocument(); | |
1269 } | |
1270 | |
1271 /// <summary> | |
1272 /// Factory method for the Document Manager object | |
1273 /// </summary> | |
1274 /// <returns>null object, since a hierarchy node does not know i
ts kind of document</returns> | |
1275 /// <remarks>Must be overriden by derived node classes if a docu
ment manager is needed</remarks> | |
1276 protected internal virtual DocumentManager GetDocumentManager() | |
1277 { | |
1278 return null; | |
1279 } | |
1280 | |
1281 /// <summary> | |
1282 /// Displays the context menu. | |
1283 /// </summary> | |
1284 /// <param name="selectedNodes">list of selected nodes.</param> | |
1285 /// <param name="pointerToVariant">contains the location (x,y) a
t which to show the menu.</param> | |
1286 [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNo
tContainTypeNames", MessageId = "pointer")] | |
1287 protected virtual int DisplayContextMenu(IList<HierarchyNode> se
lectedNodes, IntPtr pointerToVariant) | |
1288 { | |
1289 if(selectedNodes == null || selectedNodes.Count == 0 ||
pointerToVariant == IntPtr.Zero) | |
1290 { | |
1291 return NativeMethods.OLECMDERR_E_NOTSUPPORTED; | |
1292 } | |
1293 | |
1294 int idmxStoredMenu = 0; | |
1295 | |
1296 foreach(HierarchyNode node in selectedNodes) | |
1297 { | |
1298 // We check here whether we have a multiple sele
ction of | |
1299 // nodes of differing type. | |
1300 if(idmxStoredMenu == 0) | |
1301 { | |
1302 // First time through or single node cas
e | |
1303 idmxStoredMenu = node.MenuCommandId; | |
1304 } | |
1305 else if(idmxStoredMenu != node.MenuCommandId) | |
1306 { | |
1307 // We have different node types. Check i
f any of the nodes is | |
1308 // the project node and set the menu acc
ordingly. | |
1309 if(node.MenuCommandId == VsMenus.IDM_VS_
CTXT_PROJNODE) | |
1310 { | |
1311 idmxStoredMenu = VsMenus.IDM_VS_
CTXT_XPROJ_PROJITEM; | |
1312 } | |
1313 else | |
1314 { | |
1315 idmxStoredMenu = VsMenus.IDM_VS_
CTXT_XPROJ_MULTIITEM; | |
1316 } | |
1317 } | |
1318 } | |
1319 | |
1320 object variant = Marshal.GetObjectForNativeVariant(point
erToVariant); | |
1321 UInt32 pointsAsUint = (UInt32)variant; | |
1322 short x = (short)(pointsAsUint & 0x0000ffff); | |
1323 short y = (short)((pointsAsUint & 0xffff0000) / 0x10000)
; | |
1324 | |
1325 | |
1326 POINTS points = new POINTS(); | |
1327 points.x = x; | |
1328 points.y = y; | |
1329 return ShowContextMenu(idmxStoredMenu, VsMenus.guidSHLMa
inMenu, points); | |
1330 } | |
1331 | |
1332 /// <summary> | |
1333 /// Shows the specified context menu at a specified location. | |
1334 /// </summary> | |
1335 /// <param name="menuId">The context menu ID.</param> | |
1336 /// <param name="groupGuid">The GUID of the menu group.</param> | |
1337 /// <param name="points">The location at which to show the menu.
</param> | |
1338 protected virtual int ShowContextMenu(int menuId, Guid menuGroup
, POINTS points) | |
1339 { | |
1340 IVsUIShell shell = this.projectMgr.Site.GetService(typeo
f(SVsUIShell)) as IVsUIShell; | |
1341 | |
1342 Debug.Assert(shell != null, "Could not get the ui shell
from the project"); | |
1343 if(shell == null) | |
1344 { | |
1345 return VSConstants.E_FAIL; | |
1346 } | |
1347 POINTS[] pnts = new POINTS[1]; | |
1348 pnts[0].x = points.x; | |
1349 pnts[0].y = points.y; | |
1350 return shell.ShowContextMenu(0, ref menuGroup, menuId, p
nts, (Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget)this); | |
1351 } | |
1352 | |
1353 #region initiation of command execution | |
1354 /// <summary> | |
1355 /// Handles command execution. | |
1356 /// </summary> | |
1357 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1358 /// <param name="cmd">The command to be executed.</param> | |
1359 /// <param name="nCmdexecopt">Values describe how the object sho
uld execute the command.</param> | |
1360 /// <param name="pvaIn">Pointer to a VARIANTARG structure contai
ning input arguments. Can be NULL</param> | |
1361 /// <param name="pvaOut">VARIANTARG structure to receive command
output. Can be NULL.</param> | |
1362 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1363 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Cmdexecopt")] | |
1364 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "n")] | |
1365 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "pva")] | |
1366 protected virtual int ExecCommandOnNode(Guid cmdGroup, uint cmd,
uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) | |
1367 { | |
1368 if(this.projectMgr == null || this.projectMgr.IsClosed) | |
1369 { | |
1370 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1371 } | |
1372 | |
1373 if(cmdGroup == Guid.Empty) | |
1374 { | |
1375 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1376 } | |
1377 else if(cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds) | |
1378 { | |
1379 switch(cmd) | |
1380 { | |
1381 case (uint)VSConstants.VsUIHierarchyWind
owCmdIds.UIHWCMDID_DoubleClick: | |
1382 case (uint)VSConstants.VsUIHierarchyWind
owCmdIds.UIHWCMDID_EnterKey: | |
1383 this.DoDefaultAction(); | |
1384 return VSConstants.S_OK; | |
1385 } | |
1386 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1387 } | |
1388 else if(cmdGroup == VsMenus.guidStandardCommandSet97) | |
1389 { | |
1390 HierarchyNode nodeToAddTo = this.GetDragTargetHa
ndlerNode(); | |
1391 switch((VsCommands)cmd) | |
1392 { | |
1393 case VsCommands.AddNewItem: | |
1394 return nodeToAddTo.AddItemToHier
archy(HierarchyAddType.AddNewItem); | |
1395 | |
1396 case VsCommands.AddExistingItem: | |
1397 return nodeToAddTo.AddItemToHier
archy(HierarchyAddType.AddExistingItem); | |
1398 | |
1399 case VsCommands.NewFolder: | |
1400 return nodeToAddTo.AddNewFolder(
); | |
1401 | |
1402 case VsCommands.Paste: | |
1403 return this.ProjectMgr.PasteFrom
Clipboard(this); | |
1404 } | |
1405 | |
1406 } | |
1407 else if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1408 { | |
1409 switch((VsCommands2K)cmd) | |
1410 { | |
1411 case VsCommands2K.EXCLUDEFROMPROJECT: | |
1412 return this.ExcludeFromProject()
; | |
1413 } | |
1414 } | |
1415 | |
1416 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1417 } | |
1418 | |
1419 /// <summary> | |
1420 /// Executes a command that can only be executed once the whole
selection is known. | |
1421 /// </summary> | |
1422 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1423 /// <param name="cmdId">The command to be executed.</param> | |
1424 /// <param name="cmdExecOpt">Values describe how the object shou
ld execute the command.</param> | |
1425 /// <param name="vaIn">Pointer to a VARIANTARG structure contain
ing input arguments. Can be NULL</param> | |
1426 /// <param name="vaOut">VARIANTARG structure to receive command
output. Can be NULL.</param> | |
1427 /// <param name="commandOrigin">The origin of the command. From
IOleCommandTarget or hierarchy.</param> | |
1428 /// <param name="selectedNodes">The list of the selected nodes.<
/param> | |
1429 /// <param name="handled">An out parameter specifying that the c
ommand was handled.</param> | |
1430 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1431 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShould
BeCasedCorrectly", MessageId = "vaIn")] | |
1432 protected virtual int ExecCommandThatDependsOnSelectedNodes(Guid
cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin
commandOrigin, IList<HierarchyNode> selectedNodes, out bool handled) | |
1433 { | |
1434 handled = false; | |
1435 if(cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds) | |
1436 { | |
1437 switch(cmdId) | |
1438 { | |
1439 case (uint)VSConstants.VsUIHierarchyWind
owCmdIds.UIHWCMDID_RightClick: | |
1440 // The UIHWCMDID_RightClick is w
hat tells an IVsUIHierarchy in a UIHierarchyWindow | |
1441 // to put up the context menu.
Since the mouse may have moved between the | |
1442 // mouse down and the mouse up,
GetCursorPos won't tell you the right place | |
1443 // to put the context menu (espe
cially if it came through the keyboard). | |
1444 // So we pack the proper menu po
sition into pvaIn by | |
1445 // memcpy'ing a POINTS struct in
to the VT_UI4 part of the pvaIn variant. The | |
1446 // code to unpack it looks like
this: | |
1447 // ULONG ul
Pts = V_UI4(pvaIn); | |
1448 // POINTS p
ts; | |
1449 // memcpy((
void*)&pts, &ulPts, sizeof(POINTS)); | |
1450 // You then pass that POINTS int
o DisplayContextMenu. | |
1451 handled = true; | |
1452 return this.DisplayContextMenu(s
electedNodes, vaIn); | |
1453 default: | |
1454 break; | |
1455 } | |
1456 } | |
1457 else if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1458 { | |
1459 switch((VsCommands2K)cmdId) | |
1460 { | |
1461 case VsCommands2K.ViewInClassDiagram: | |
1462 handled = true; | |
1463 return this.ShowInDesigner(selec
tedNodes); | |
1464 } | |
1465 } | |
1466 | |
1467 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1468 } | |
1469 | |
1470 /// <summary> | |
1471 /// Executes command that are independent of a selection. | |
1472 /// </summary> | |
1473 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1474 /// <param name="cmdId">The command to be executed.</param> | |
1475 /// <param name="cmdExecOpt">Values describe how the object shou
ld execute the command.</param> | |
1476 /// <param name="vaIn">Pointer to a VARIANTARG structure contain
ing input arguments. Can be NULL</param> | |
1477 /// <param name="vaOut">VARIANTARG structure to receive command
output. Can be NULL.</param> | |
1478 /// <param name="commandOrigin">The origin of the command. From
IOleCommandTarget or hierarchy.</param> | |
1479 /// <param name="handled">An out parameter specifying that the c
ommand was handled.</param> | |
1480 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1481 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShould
BeCasedCorrectly", MessageId = "vaIn")] | |
1482 protected virtual int ExecCommandIndependentOfSelection(Guid cmd
Group, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin com
mandOrigin, out bool handled) | |
1483 { | |
1484 handled = false; | |
1485 | |
1486 if(this.projectMgr == null || this.projectMgr.IsClosed) | |
1487 { | |
1488 return VSConstants.E_FAIL; | |
1489 } | |
1490 | |
1491 if(cmdGroup == VsMenus.guidStandardCommandSet97) | |
1492 { | |
1493 if(commandOrigin == CommandOrigin.OleCommandTarg
et) | |
1494 { | |
1495 switch((VsCommands)cmdId) | |
1496 { | |
1497 case VsCommands.Cut: | |
1498 case VsCommands.Copy: | |
1499 case VsCommands.Paste: | |
1500 case VsCommands.Rename: | |
1501 handled = true; | |
1502 return (int)OleConstants
.OLECMDERR_E_NOTSUPPORTED; | |
1503 } | |
1504 } | |
1505 | |
1506 switch((VsCommands)cmdId) | |
1507 { | |
1508 case VsCommands.Copy: | |
1509 handled = true; | |
1510 return this.ProjectMgr.CopyToCli
pboard(); | |
1511 | |
1512 case VsCommands.Cut: | |
1513 handled = true; | |
1514 return this.ProjectMgr.CutToClip
board(); | |
1515 | |
1516 case VsCommands.SolutionCfg: | |
1517 handled = true; | |
1518 return (int)OleConstants.OLECMDE
RR_E_NOTSUPPORTED; | |
1519 | |
1520 case VsCommands.SearchCombo: | |
1521 handled = true; | |
1522 return (int)OleConstants.OLECMDE
RR_E_NOTSUPPORTED; | |
1523 | |
1524 } | |
1525 } | |
1526 else if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1527 { | |
1528 // There should only be the project node who han
dles these and should manifest in the same action regardles of selection. | |
1529 switch((VsCommands2K)cmdId) | |
1530 { | |
1531 case VsCommands2K.SHOWALLFILES: | |
1532 handled = true; | |
1533 return this.projectMgr.ShowAllFi
les(); | |
1534 case VsCommands2K.ADDREFERENCE: | |
1535 handled = true; | |
1536 return this.projectMgr.AddProjec
tReference(); | |
1537 case VsCommands2K.ADDWEBREFERENCE: | |
1538 handled = true; | |
1539 return this.projectMgr.AddWebRef
erence(); | |
1540 } | |
1541 } | |
1542 | |
1543 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1544 } | |
1545 | |
1546 /// <summary> | |
1547 /// The main entry point for command excection. Gets called from
the IVsUIHierarchy and IOleCommandTarget methods. | |
1548 /// </summary> | |
1549 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1550 /// <param name="cmdId">The command to be executed.</param> | |
1551 /// <param name="cmdExecOpt">Values describe how the object shou
ld execute the command.</param> | |
1552 /// <param name="vaIn">Pointer to a VARIANTARG structure contain
ing input arguments. Can be NULL</param> | |
1553 /// <param name="vaOut">VARIANTARG structure to receive command
output. Can be NULL.</param> | |
1554 /// <param name="commandOrigin">The origin of the command. From
IOleCommandTarget or hierarchy.</param> | |
1555 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1556 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShould
BeCasedCorrectly", MessageId = "vaIn")] | |
1557 protected virtual int InternalExecCommand(Guid cmdGroup, uint cm
dId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin) | |
1558 { | |
1559 CCITracing.TraceCall(cmdGroup.ToString() + "," + cmdId.T
oString()); | |
1560 if(this.projectMgr == null || this.projectMgr.IsClosed) | |
1561 { | |
1562 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1563 } | |
1564 | |
1565 if(cmdGroup == Guid.Empty) | |
1566 { | |
1567 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1568 } | |
1569 | |
1570 IList<HierarchyNode> selectedNodes = this.projectMgr.Get
SelectedNodes(); | |
1571 | |
1572 // Check if all nodes can execute a command. If there is
at least one that cannot return not handled. | |
1573 foreach(HierarchyNode node in selectedNodes) | |
1574 { | |
1575 if(!node.CanExecuteCommand) | |
1576 { | |
1577 return (int)OleConstants.OLECMDERR_E_NOT
SUPPORTED; | |
1578 } | |
1579 } | |
1580 | |
1581 // Handle commands that are independent of a selection. | |
1582 bool handled = false; | |
1583 int returnValue = this.ExecCommandIndependentOfSelection
(cmdGroup, cmdId, cmdExecOpt, vaIn, vaOut, commandOrigin, out handled); | |
1584 if(handled) | |
1585 { | |
1586 return returnValue; | |
1587 } | |
1588 | |
1589 | |
1590 // Now handle commands that need the selected nodes as i
nput parameter. | |
1591 returnValue = this.ExecCommandThatDependsOnSelectedNodes
(cmdGroup, cmdId, cmdExecOpt, vaIn, vaOut, commandOrigin, selectedNodes, out han
dled); | |
1592 if(handled) | |
1593 { | |
1594 return returnValue; | |
1595 } | |
1596 | |
1597 returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED
; | |
1598 | |
1599 // Handle commands iteratively. The same action will be
executed for all of the selected items. | |
1600 foreach(HierarchyNode node in selectedNodes) | |
1601 { | |
1602 try | |
1603 { | |
1604 returnValue = node.ExecCommandOnNode(cmd
Group, cmdId, cmdExecOpt, vaIn, vaOut); | |
1605 } | |
1606 catch(COMException e) | |
1607 { | |
1608 Trace.WriteLine("Exception : " + e.Messa
ge); | |
1609 returnValue = e.ErrorCode; | |
1610 } | |
1611 if(returnValue != VSConstants.S_OK) | |
1612 { | |
1613 break; | |
1614 } | |
1615 } | |
1616 | |
1617 if(returnValue == VSConstants.E_ABORT || returnValue ==
VSConstants.OLE_E_PROMPTSAVECANCELLED) | |
1618 { | |
1619 returnValue = VSConstants.S_OK; | |
1620 } | |
1621 | |
1622 return returnValue; | |
1623 } | |
1624 | |
1625 #endregion | |
1626 | |
1627 #region query command handling | |
1628 /// <summary> | |
1629 /// Handles menus originating from IOleCommandTarget. | |
1630 /// </summary> | |
1631 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1632 /// <param name="cmd">The command to be executed.</param> | |
1633 /// <param name="handled">Specifies whether the menu was handled
.</param> | |
1634 /// <returns>A QueryStatusResult describing the status of the me
nu.</returns> | |
1635 protected virtual QueryStatusResult QueryStatusCommandFromOleCom
mandTarget(Guid cmdGroup, uint cmd, out bool handled) | |
1636 { | |
1637 handled = false; | |
1638 // NOTE: We only want to support Cut/Copy/Paste/Delete/R
ename commands | |
1639 // if focus is in the project window. This means that we
should only | |
1640 // support these commands if they are dispatched via IVs
UIHierarchy | |
1641 // interface and not if they are dispatch through IOleCo
mmandTarget | |
1642 // during the command routing to the active project/hier
archy. | |
1643 if(VsMenus.guidStandardCommandSet97 == cmdGroup) | |
1644 { | |
1645 | |
1646 switch((VsCommands)cmd) | |
1647 { | |
1648 case VsCommands.Copy: | |
1649 case VsCommands.Paste: | |
1650 case VsCommands.Cut: | |
1651 case VsCommands.Rename: | |
1652 handled = true; | |
1653 return QueryStatusResult.NOTSUPP
ORTED; | |
1654 } | |
1655 } | |
1656 // The reference menu and the web reference menu should
always be shown. | |
1657 else if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1658 { | |
1659 switch((VsCommands2K)cmd) | |
1660 { | |
1661 case VsCommands2K.ADDREFERENCE: | |
1662 handled = true; | |
1663 return QueryStatusResult.SUPPORT
ED | QueryStatusResult.ENABLED; | |
1664 } | |
1665 } | |
1666 return QueryStatusResult.NOTSUPPORTED; | |
1667 } | |
1668 | |
1669 /// <summary> | |
1670 /// Specifies which command does not support multiple selection
and should be disabled if multi-selected. | |
1671 /// </summary> | |
1672 /// <param name="cmdGroup">Unique identifier of the command grou
p</param> | |
1673 /// <param name="cmd">The command to be executed.</param> | |
1674 /// <param name="selectedNodes">The list of selected nodes.</par
am> | |
1675 /// <param name="handled">Specifies whether the menu was handled
.</param> | |
1676 /// <returns>A QueryStatusResult describing the status of the me
nu.</returns> | |
1677 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Multi")] | |
1678 protected virtual QueryStatusResult DisableCommandOnNodesThatDoN
otSupportMultiSelection(Guid cmdGroup, uint cmd, IList<HierarchyNode> selectedNo
des, out bool handled) | |
1679 { | |
1680 handled = false; | |
1681 QueryStatusResult queryResult = QueryStatusResult.NOTSUP
PORTED; | |
1682 if(selectedNodes == null || selectedNodes.Count == 1) | |
1683 { | |
1684 return queryResult; | |
1685 } | |
1686 | |
1687 if(VsMenus.guidStandardCommandSet97 == cmdGroup) | |
1688 { | |
1689 switch((VsCommands)cmd) | |
1690 { | |
1691 case VsCommands.Cut: | |
1692 case VsCommands.Copy: | |
1693 // If the project node is select
ed then cut and copy is not supported. | |
1694 if(selectedNodes.Contains(this.p
rojectMgr)) | |
1695 { | |
1696 queryResult = QueryStatu
sResult.SUPPORTED | QueryStatusResult.INVISIBLE; | |
1697 handled = true; | |
1698 } | |
1699 break; | |
1700 | |
1701 case VsCommands.Paste: | |
1702 case VsCommands.NewFolder: | |
1703 queryResult = QueryStatusResult.
SUPPORTED | QueryStatusResult.INVISIBLE; | |
1704 handled = true; | |
1705 break; | |
1706 } | |
1707 } | |
1708 else if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1709 { | |
1710 switch((VsCommands2K)cmd) | |
1711 { | |
1712 case VsCommands2K.QUICKOBJECTSEARCH: | |
1713 case VsCommands2K.SETASSTARTPAGE: | |
1714 case VsCommands2K.ViewInClassDiagram: | |
1715 queryResult = QueryStatusResult.
SUPPORTED | QueryStatusResult.INVISIBLE; | |
1716 handled = true; | |
1717 break; | |
1718 } | |
1719 } | |
1720 | |
1721 return queryResult; | |
1722 } | |
1723 | |
1724 /// <summary> | |
1725 /// Handles command status on a node. Should be overridden by de
scendant nodes. If a command cannot be handled then the base should be called. | |
1726 /// </summary> | |
1727 /// <param name="cmdGroup">A unique identifier of the command gr
oup. The pguidCmdGroup parameter can be NULL to specify the standard group.</par
am> | |
1728 /// <param name="cmd">The command to query status for.</param> | |
1729 /// <param name="pCmdText">Pointer to an OLECMDTEXT structure in
which to return the name and/or status information of a single command. Can be
NULL to indicate that the caller does not require this information.</param> | |
1730 /// <param name="result">An out parameter specifying the QuerySt
atusResult of the command.</param> | |
1731 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1732 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "p")] | |
1733 protected virtual int QueryStatusOnNode(Guid cmdGroup, uint cmd,
IntPtr pCmdText, ref QueryStatusResult result) | |
1734 { | |
1735 if(cmdGroup == VsMenus.guidStandardCommandSet2K) | |
1736 { | |
1737 if((VsCommands2K)cmd == VsCommands2K.SHOWALLFILE
S) | |
1738 { | |
1739 result |= QueryStatusResult.SUPPORTED |
QueryStatusResult.ENABLED; | |
1740 return VSConstants.S_OK; | |
1741 } | |
1742 } | |
1743 | |
1744 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1745 } | |
1746 | |
1747 /// <summary> | |
1748 /// Disables commands when the project is in run/break mode. | |
1749 /// </summary>/ | |
1750 /// <param name="commandGroup">Unique identifier of the command
group</param> | |
1751 /// <param name="command">The command to be executed.</param> | |
1752 /// <returns>A QueryStatusResult describing the status of the me
nu.</returns> | |
1753 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Main
tainability", "CA1502:AvoidExcessiveComplexity"), SuppressMessage("Microsoft.Nam
ing", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "InCurrent")] | |
1754 protected virtual bool DisableCmdInCurrentMode(Guid commandGroup
, uint command) | |
1755 { | |
1756 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
1757 { | |
1758 return false; | |
1759 } | |
1760 | |
1761 // Don't ask if it is not these two commandgroups. | |
1762 if(commandGroup == VsMenus.guidStandardCommandSet97 || c
ommandGroup == VsMenus.guidStandardCommandSet2K) | |
1763 { | |
1764 if(this.ProjectMgr.IsCurrentStateASuppressComman
dsMode()) | |
1765 { | |
1766 if(commandGroup == VsMenus.guidStandardC
ommandSet97) | |
1767 { | |
1768 switch((VsCommands)command) | |
1769 { | |
1770 default: | |
1771 break; | |
1772 case VsCommands.AddExist
ingItem: | |
1773 case VsCommands.AddNewIt
em: | |
1774 case VsCommands.NewFolde
r: | |
1775 case VsCommands.Remove: | |
1776 case VsCommands.Cut: | |
1777 case VsCommands.Paste: | |
1778 case VsCommands.Copy: | |
1779 case VsCommands.EditLabe
l: | |
1780 case VsCommands.Rename: | |
1781 case VsCommands.UnloadPr
oject: | |
1782 return true; | |
1783 } | |
1784 } | |
1785 else if(commandGroup == VsMenus.guidStan
dardCommandSet2K) | |
1786 { | |
1787 switch((VsCommands2K)command) | |
1788 { | |
1789 default: | |
1790 break; | |
1791 case VsCommands2K.EXCLUD
EFROMPROJECT: | |
1792 case VsCommands2K.INCLUD
EINPROJECT: | |
1793 case VsCommands2K.ADDWEB
REFERENCECTX: | |
1794 case VsCommands2K.ADDWEB
REFERENCE: | |
1795 case VsCommands2K.ADDREF
ERENCE: | |
1796 case VsCommands2K.SETASS
TARTPAGE: | |
1797 return true; | |
1798 } | |
1799 } | |
1800 } | |
1801 // If we are not in a cut or copy mode then disa
ble the paste command | |
1802 else if(!this.ProjectMgr.AllowPasteCommand()) | |
1803 { | |
1804 if(commandGroup == VsMenus.guidStandardC
ommandSet97 && (VsCommands)command == VsCommands.Paste) | |
1805 { | |
1806 return true; | |
1807 } | |
1808 } | |
1809 } | |
1810 | |
1811 return false; | |
1812 } | |
1813 | |
1814 | |
1815 /// <summary> | |
1816 /// Queries the object for the command status on a list of selec
ted nodes. | |
1817 /// </summary> | |
1818 /// <param name="cmdGroup">A unique identifier of the command gr
oup.</param> | |
1819 /// <param name="cCmds">The number of commands in the prgCmds ar
ray</param> | |
1820 /// <param name="prgCmds">A caller-allocated array of OLECMD str
uctures that indicate the commands for which the caller requires status informat
ion. This method fills the cmdf member of each structure with values taken from
the OLECMDF enumeration</param> | |
1821 /// <param name="pCmdText">Pointer to an OLECMDTEXT structure in
which to return the name and/or status information of a single command. Can be
NULL to indicate that the caller does not require this information. </param> | |
1822 /// <param name="commandOrigin">Specifies the origin of the comm
and. Either it was called from the QueryStatusCommand on IVsUIHierarchy or from
the IOleCommandTarget</param> | |
1823 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
1824 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Cmds")] | |
1825 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "c")] | |
1826 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "p")] | |
1827 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "prg")] | |
1828 protected virtual int QueryStatusSelection(Guid cmdGroup, uint c
Cmds, OLECMD[] prgCmds, IntPtr pCmdText, CommandOrigin commandOrigin) | |
1829 { | |
1830 if(this.projectMgr.IsClosed) | |
1831 { | |
1832 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTE
D; | |
1833 } | |
1834 | |
1835 if(cmdGroup == Guid.Empty) | |
1836 { | |
1837 return (int)OleConstants.OLECMDERR_E_UNKNOWNGROU
P; | |
1838 } | |
1839 | |
1840 uint cmd = prgCmds[0].cmdID; | |
1841 QueryStatusResult queryResult = QueryStatusResult.NOTSUP
PORTED; | |
1842 | |
1843 // For now ask this node (that is the project node) to d
isable or enable a node. | |
1844 // This is an optimization. Why should we ask each node
for its current state? They all are in the same state. | |
1845 // Also please note that we return QueryStatusResult.INV
ISIBLE instead of just QueryStatusResult.SUPPORTED. | |
1846 // The reason is that if the project has nested projects
, then providing just QueryStatusResult.SUPPORTED is not enough. | |
1847 // What will happen is that the nested project will show
grayed commands that belong to this project and does not belong to the nested p
roject. (like special commands implemented by subclassed projects). | |
1848 // The reason is that a special command comes in that is
not handled because we are in debug mode. Then VsCore asks the nested project c
an you handle it. | |
1849 // The nested project does not know about it, thus it sh
ows it on the nested project as grayed. | |
1850 if(this.DisableCmdInCurrentMode(cmdGroup, cmd)) | |
1851 { | |
1852 queryResult = QueryStatusResult.SUPPORTED | Quer
yStatusResult.INVISIBLE; | |
1853 } | |
1854 else | |
1855 { | |
1856 bool handled = false; | |
1857 | |
1858 if(commandOrigin == CommandOrigin.OleCommandTarg
et) | |
1859 { | |
1860 queryResult = this.QueryStatusCommandFro
mOleCommandTarget(cmdGroup, cmd, out handled); | |
1861 } | |
1862 | |
1863 if(!handled) | |
1864 { | |
1865 IList<HierarchyNode> selectedNodes = thi
s.projectMgr.GetSelectedNodes(); | |
1866 | |
1867 // Want to disable in multiselect case. | |
1868 if(selectedNodes != null && selectedNode
s.Count > 1) | |
1869 { | |
1870 queryResult = this.DisableComman
dOnNodesThatDoNotSupportMultiSelection(cmdGroup, cmd, selectedNodes, out handled
); | |
1871 } | |
1872 | |
1873 // Now go and do the job on the nodes. | |
1874 if(!handled) | |
1875 { | |
1876 queryResult = this.QueryStatusSe
lectionOnNodes(selectedNodes, cmdGroup, cmd, pCmdText); | |
1877 } | |
1878 | |
1879 } | |
1880 } | |
1881 | |
1882 // Process the results set in the QueryStatusResult | |
1883 if(queryResult != QueryStatusResult.NOTSUPPORTED) | |
1884 { | |
1885 // Set initial value | |
1886 prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTE
D; | |
1887 | |
1888 if((queryResult & QueryStatusResult.ENABLED) !=
0) | |
1889 { | |
1890 prgCmds[0].cmdf |= (uint)OLECMDF.OLECMDF
_ENABLED; | |
1891 } | |
1892 | |
1893 if((queryResult & QueryStatusResult.INVISIBLE) !
= 0) | |
1894 { | |
1895 prgCmds[0].cmdf |= (uint)OLECMDF.OLECMDF
_INVISIBLE; | |
1896 } | |
1897 | |
1898 if((queryResult & QueryStatusResult.LATCHED) !=
0) | |
1899 { | |
1900 prgCmds[0].cmdf |= (uint)OLECMDF.OLECMDF
_LATCHED; | |
1901 } | |
1902 | |
1903 return VSConstants.S_OK; | |
1904 } | |
1905 | |
1906 return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; | |
1907 } | |
1908 | |
1909 /// <summary> | |
1910 /// Queries the selected nodes for the command status. | |
1911 /// A command is supported iff any nodes supports it. | |
1912 /// A command is enabled iff all nodes enable it. | |
1913 /// A command is invisible iff any node sets invisibility. | |
1914 /// A command is latched only if all are latched. | |
1915 /// </summary> | |
1916 /// <param name="selectedNodes">The list of selected nodes.</par
am> | |
1917 /// <param name="cmdGroup">A unique identifier of the command gr
oup.</param> | |
1918 /// <param name="cmd">The command id to query for.</param> | |
1919 /// <param name="pCmdText">Pointer to an OLECMDTEXT structure in
which to return the name and/or status information of a single command. Can be
NULL to indicate that the caller does not require this information. </param> | |
1920 /// <returns>Retuns the result of the query on the slected nodes
.</returns> | |
1921 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "p")] | |
1922 protected virtual QueryStatusResult QueryStatusSelectionOnNodes(
IList<HierarchyNode> selectedNodes, Guid cmdGroup, uint cmd, IntPtr pCmdText) | |
1923 { | |
1924 if(selectedNodes == null || selectedNodes.Count == 0) | |
1925 { | |
1926 return QueryStatusResult.NOTSUPPORTED; | |
1927 } | |
1928 | |
1929 int result = 0; | |
1930 bool supported = false; | |
1931 bool enabled = true; | |
1932 bool invisible = false; | |
1933 bool latched = true; | |
1934 QueryStatusResult tempQueryResult = QueryStatusResult.NO
TSUPPORTED; | |
1935 | |
1936 foreach(HierarchyNode node in selectedNodes) | |
1937 { | |
1938 result = node.QueryStatusOnNode(cmdGroup, cmd, p
CmdText, ref tempQueryResult); | |
1939 if(result < 0) | |
1940 { | |
1941 break; | |
1942 } | |
1943 | |
1944 // cmd is supported iff any node supports cmd | |
1945 // cmd is enabled iff all nodes enable cmd | |
1946 // cmd is invisible iff any node sets invisibili
ty | |
1947 // cmd is latched only if all are latched. | |
1948 supported = supported || ((tempQueryResult & Que
ryStatusResult.SUPPORTED) != 0); | |
1949 enabled = enabled && ((tempQueryResult & QuerySt
atusResult.ENABLED) != 0); | |
1950 invisible = invisible || ((tempQueryResult & Que
ryStatusResult.INVISIBLE) != 0); | |
1951 latched = latched && ((tempQueryResult & QuerySt
atusResult.LATCHED) != 0); | |
1952 } | |
1953 | |
1954 QueryStatusResult queryResult = QueryStatusResult.NOTSUP
PORTED; | |
1955 | |
1956 if(result >= 0 && supported) | |
1957 { | |
1958 queryResult = QueryStatusResult.SUPPORTED; | |
1959 | |
1960 if(enabled) | |
1961 { | |
1962 queryResult |= QueryStatusResult.ENABLED
; | |
1963 } | |
1964 | |
1965 if(invisible) | |
1966 { | |
1967 queryResult |= QueryStatusResult.INVISIB
LE; | |
1968 } | |
1969 | |
1970 if(latched) | |
1971 { | |
1972 queryResult |= QueryStatusResult.LATCHED
; | |
1973 } | |
1974 } | |
1975 | |
1976 return queryResult; | |
1977 } | |
1978 | |
1979 #endregion | |
1980 protected virtual bool CanDeleteItem(__VSDELETEITEMOPERATION del
eteOperation) | |
1981 { | |
1982 return this.ProjectMgr.CanProjectDeleteItems; | |
1983 } | |
1984 | |
1985 /// <summary> | |
1986 /// Overwrite this method to tell that you support the default i
con for this node. | |
1987 /// </summary> | |
1988 /// <returns></returns> | |
1989 protected virtual bool CanShowDefaultIcon() | |
1990 { | |
1991 return false; | |
1992 } | |
1993 | |
1994 /// <summary> | |
1995 /// Performs save as operation for an item after the save as dia
log has been processed. | |
1996 /// </summary> | |
1997 /// <param name="docData">A pointer to the rdt</param> | |
1998 /// <param name="newName">The newName of the item</param> | |
1999 /// <returns></returns> | |
2000 protected virtual int AfterSaveItemAs(IntPtr docData, string new
Name) | |
2001 { | |
2002 throw new NotImplementedException(); | |
2003 } | |
2004 | |
2005 /// <summary> | |
2006 /// The method that does the cleanup. | |
2007 /// </summary> | |
2008 /// <param name="disposing">Is the Dispose called by some intern
al member, or it is called by from GC.</param> | |
2009 protected virtual void Dispose(bool disposing) | |
2010 { | |
2011 if(this.isDisposed) | |
2012 { | |
2013 return; | |
2014 } | |
2015 | |
2016 if(disposing) | |
2017 { | |
2018 // This will dispose any subclassed project node
that implements IDisposable. | |
2019 if(this.oleServiceProvider != null) | |
2020 { | |
2021 // Dispose the ole service provider obje
ct. | |
2022 this.oleServiceProvider.Dispose(); | |
2023 } | |
2024 } | |
2025 | |
2026 this.isDisposed = true; | |
2027 } | |
2028 | |
2029 /// <summary> | |
2030 /// Sets the VSADDFILEFLAGS that will be used to call the IVsTr
ackProjectDocumentsEvents2 OnAddFiles | |
2031 /// </summary> | |
2032 /// <param name="files">The files to which an array of VSADDFILE
FLAGS has to be specified.</param> | |
2033 /// <returns></returns> | |
2034 protected internal virtual VSADDFILEFLAGS[] GetAddFileFlags(stri
ng[] files) | |
2035 { | |
2036 if(files == null || files.Length == 0) | |
2037 { | |
2038 return new VSADDFILEFLAGS[1] { VSADDFILEFLAGS.VS
ADDFILEFLAGS_NoFlags }; | |
2039 } | |
2040 | |
2041 VSADDFILEFLAGS[] addFileFlags = new VSADDFILEFLAGS[files
.Length]; | |
2042 | |
2043 for(int i = 0; i < files.Length; i++) | |
2044 { | |
2045 addFileFlags[i] = VSADDFILEFLAGS.VSADDFILEFLAGS_
NoFlags; | |
2046 } | |
2047 | |
2048 return addFileFlags; | |
2049 } | |
2050 | |
2051 /// <summary> | |
2052 /// Sets the VSQUERYADDFILEFLAGS that will be used to call the
IVsTrackProjectDocumentsEvents2 OnQueryAddFiles | |
2053 /// </summary> | |
2054 /// <param name="files">The files to which an array of VSADDFILE
FLAGS has to be specified.</param> | |
2055 /// <returns></returns> | |
2056 protected internal virtual VSQUERYADDFILEFLAGS[] GetQueryAddFile
Flags(string[] files) | |
2057 { | |
2058 if(files == null || files.Length == 0) | |
2059 { | |
2060 return new VSQUERYADDFILEFLAGS[1] { VSQUERYADDFI
LEFLAGS.VSQUERYADDFILEFLAGS_NoFlags }; | |
2061 } | |
2062 | |
2063 VSQUERYADDFILEFLAGS[] queryAddFileFlags = new VSQUERYADD
FILEFLAGS[files.Length]; | |
2064 | |
2065 for(int i = 0; i < files.Length; i++) | |
2066 { | |
2067 queryAddFileFlags[i] = VSQUERYADDFILEFLAGS.VSQUE
RYADDFILEFLAGS_NoFlags; | |
2068 } | |
2069 | |
2070 return queryAddFileFlags; | |
2071 } | |
2072 | |
2073 /// <summary> | |
2074 /// Sets the VSREMOVEFILEFLAGS that will be used to call the IV
sTrackProjectDocumentsEvents2 OnRemoveFiles | |
2075 /// </summary> | |
2076 /// <param name="files">The files to which an array of VSREMOVEF
ILEFLAGS has to be specified.</param> | |
2077 /// <returns></returns> | |
2078 protected internal virtual VSREMOVEFILEFLAGS[] GetRemoveFileFlag
s(string[] files) | |
2079 { | |
2080 if(files == null || files.Length == 0) | |
2081 { | |
2082 return new VSREMOVEFILEFLAGS[1] { VSREMOVEFILEFL
AGS.VSREMOVEFILEFLAGS_NoFlags }; | |
2083 } | |
2084 | |
2085 VSREMOVEFILEFLAGS[] removeFileFlags = new VSREMOVEFILEFL
AGS[files.Length]; | |
2086 | |
2087 for(int i = 0; i < files.Length; i++) | |
2088 { | |
2089 removeFileFlags[i] = VSREMOVEFILEFLAGS.VSREMOVEF
ILEFLAGS_NoFlags; | |
2090 } | |
2091 | |
2092 return removeFileFlags; | |
2093 } | |
2094 | |
2095 /// <summary> | |
2096 /// Sets the VSQUERYREMOVEFILEFLAGS that will be used to call th
e IVsTrackProjectDocumentsEvents2 OnQueryRemoveFiles | |
2097 /// </summary> | |
2098 /// <param name="files">The files to which an array of VSQUERYRE
MOVEFILEFLAGS has to be specified.</param> | |
2099 /// <returns></returns> | |
2100 protected internal virtual VSQUERYREMOVEFILEFLAGS[] GetQueryRemo
veFileFlags(string[] files) | |
2101 { | |
2102 if(files == null || files.Length == 0) | |
2103 { | |
2104 return new VSQUERYREMOVEFILEFLAGS[1] { VSQUERYRE
MOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags }; | |
2105 } | |
2106 | |
2107 VSQUERYREMOVEFILEFLAGS[] queryRemoveFileFlags = new VSQU
ERYREMOVEFILEFLAGS[files.Length]; | |
2108 | |
2109 for(int i = 0; i < files.Length; i++) | |
2110 { | |
2111 queryRemoveFileFlags[i] = VSQUERYREMOVEFILEFLAGS
.VSQUERYREMOVEFILEFLAGS_NoFlags; | |
2112 } | |
2113 | |
2114 return queryRemoveFileFlags; | |
2115 } | |
2116 | |
2117 /// <summary> | |
2118 /// This method should be overridden to provide the list of file
s and associated flags for source control. | |
2119 /// </summary> | |
2120 /// <param name="files">The list of files to be placed under sou
rce control.</param> | |
2121 /// <param name="flags">The flags that are associated to the fil
es.</param> | |
2122 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Scc")] | |
2123 protected internal virtual void GetSccFiles(IList<string> files,
IList<tagVsSccFilesFlags> flags) | |
2124 { | |
2125 if(this.ExcludeNodeFromScc) | |
2126 { | |
2127 return; | |
2128 } | |
2129 | |
2130 if(files == null) | |
2131 { | |
2132 throw new ArgumentNullException("files"); | |
2133 } | |
2134 | |
2135 if(flags == null) | |
2136 { | |
2137 throw new ArgumentNullException("flags"); | |
2138 } | |
2139 | |
2140 files.Add(this.GetMkDocument()); | |
2141 | |
2142 tagVsSccFilesFlags flagsToAdd = (this.firstChild != null
&& (this.firstChild is DependentFileNode)) ? tagVsSccFilesFlags.SFF_HasSpecialF
iles : tagVsSccFilesFlags.SFF_NoFlags; | |
2143 | |
2144 flags.Add(flagsToAdd); | |
2145 } | |
2146 | |
2147 /// <summary> | |
2148 /// This method should be overridden to provide the list of spec
ial files and associated flags for source control. | |
2149 /// </summary> | |
2150 /// <param name="sccFile">One of the file associated to the node
.</param> | |
2151 /// <param name="files">The list of files to be placed under sou
rce control.</param> | |
2152 /// <param name="flags">The flags that are associated to the fil
es.</param> | |
2153 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Scc")] | |
2154 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "scc")] | |
2155 protected internal virtual void GetSccSpecialFiles(string sccFil
e, IList<string> files, IList<tagVsSccFilesFlags> flags) | |
2156 { | |
2157 if(this.ExcludeNodeFromScc) | |
2158 { | |
2159 return; | |
2160 } | |
2161 | |
2162 if(files == null) | |
2163 { | |
2164 throw new ArgumentNullException("files"); | |
2165 } | |
2166 | |
2167 if(flags == null) | |
2168 { | |
2169 throw new ArgumentNullException("flags"); | |
2170 } | |
2171 } | |
2172 | |
2173 /// <summary> | |
2174 /// Delete the item corresponding to the specified path from sto
rage. | |
2175 /// </summary> | |
2176 /// <param name="path">Url of the item to delete</param> | |
2177 internal protected virtual void DeleteFromStorage(string path) | |
2178 { | |
2179 } | |
2180 | |
2181 /// <summary> | |
2182 /// Determines whether a file change should be ignored or not. | |
2183 /// </summary> | |
2184 /// <param name="ignoreFlag">Flag indicating whether or not to i
gnore changes (true to ignore changes).</param> | |
2185 protected internal virtual void IgnoreItemFileChanges(bool ignor
eFlag) | |
2186 { | |
2187 } | |
2188 | |
2189 /// <summary> | |
2190 /// Called to determine whether a project item is reloadable. | |
2191 /// </summary> | |
2192 /// <returns>True if the project item is reloadable.</returns> | |
2193 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Reloadable")] | |
2194 protected internal virtual bool IsItemReloadable() | |
2195 { | |
2196 return true; | |
2197 } | |
2198 | |
2199 /// <summary> | |
2200 /// Reloads an item. | |
2201 /// </summary> | |
2202 /// <param name="reserved">Reserved parameter defined at the IVs
PersistHierarchyItem2::ReloadItem parameter.</param> | |
2203 protected internal virtual void ReloadItem(uint reserved) | |
2204 { | |
2205 | |
2206 } | |
2207 | |
2208 /// <summary> | |
2209 /// Handle the Copy operation to the clipboard | |
2210 /// This method is typically overriden on the project node | |
2211 /// </summary> | |
2212 protected internal virtual int CopyToClipboard() | |
2213 { | |
2214 return VSConstants.E_NOTIMPL; | |
2215 } | |
2216 | |
2217 /// <summary> | |
2218 /// Handle the Cut operation to the clipboard | |
2219 /// This method is typically overriden on the project node | |
2220 /// </summary> | |
2221 protected internal virtual int CutToClipboard() | |
2222 { | |
2223 return VSConstants.E_NOTIMPL; | |
2224 } | |
2225 | |
2226 /// <summary> | |
2227 /// Handle the paste from Clipboard command. | |
2228 /// This method is typically overriden on the project node | |
2229 /// </summary> | |
2230 protected internal virtual int PasteFromClipboard(HierarchyNode
targetNode) | |
2231 { | |
2232 return VSConstants.E_NOTIMPL; | |
2233 } | |
2234 | |
2235 /// <summary> | |
2236 /// Determines if the paste command should be allowed. | |
2237 /// This method is typically overriden on the project node | |
2238 /// </summary> | |
2239 protected internal virtual bool AllowPasteCommand() | |
2240 { | |
2241 return false; ; | |
2242 } | |
2243 | |
2244 /// <summary> | |
2245 /// Register/Unregister for Clipboard events for the UiHierarchy
Window (solution explorer) | |
2246 /// This method is typically overriden on the project node | |
2247 /// </summary> | |
2248 /// <param name="value">true for register, false for unregister<
/param> | |
2249 protected internal virtual void RegisterClipboardNotifications(b
ool value) | |
2250 { | |
2251 return; | |
2252 } | |
2253 #endregion | |
2254 | |
2255 #region public methods | |
2256 | |
2257 public void OnItemAdded(HierarchyNode parent, HierarchyNode chil
d) | |
2258 { | |
2259 if(null != parent.onChildAdded) | |
2260 { | |
2261 HierarchyNodeEventArgs args = new HierarchyNodeE
ventArgs(child); | |
2262 parent.onChildAdded(parent, args); | |
2263 } | |
2264 if(parent == null) | |
2265 { | |
2266 throw new ArgumentNullException("parent"); | |
2267 } | |
2268 | |
2269 if(child == null) | |
2270 { | |
2271 throw new ArgumentNullException("child"); | |
2272 } | |
2273 | |
2274 HierarchyNode foo; | |
2275 foo = this.projectMgr == null ? this : this.projectMgr; | |
2276 | |
2277 if(foo == this.projectMgr && (this.projectMgr.EventTrigg
eringFlag & ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents) != 0) | |
2278 { | |
2279 return; | |
2280 } | |
2281 | |
2282 HierarchyNode prev = child.PreviousSibling; | |
2283 uint prevId = (prev != null) ? prev.hierarchyId : VSCons
tants.VSITEMID_NIL; | |
2284 foreach(IVsHierarchyEvents sink in foo.hierarchyEventSin
ks) | |
2285 { | |
2286 int result = sink.OnItemAdded(parent.hierarchyId
, prevId, child.hierarchyId); | |
2287 if(ErrorHandler.Failed(result) && result != VSCo
nstants.E_NOTIMPL) | |
2288 { | |
2289 ErrorHandler.ThrowOnFailure(result); | |
2290 } | |
2291 } | |
2292 } | |
2293 | |
2294 | |
2295 public void OnItemDeleted() | |
2296 { | |
2297 HierarchyNode foo; | |
2298 foo = this.projectMgr == null ? this : this.projectMgr; | |
2299 | |
2300 if(foo == this.projectMgr && (this.projectMgr.EventTrigg
eringFlag & ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents) != 0) | |
2301 { | |
2302 return; | |
2303 } | |
2304 | |
2305 if(foo.hierarchyEventSinks.Count > 0) | |
2306 { | |
2307 // Note that in some cases (deletion of project
node for example), an Advise | |
2308 // may be removed while we are iterating over it
. To get around this problem we | |
2309 // take a snapshot of the advise list and walk t
hat. | |
2310 List<IVsHierarchyEvents> clonedSink = new List<I
VsHierarchyEvents>(); | |
2311 | |
2312 foreach(IVsHierarchyEvents anEvent in foo.hierar
chyEventSinks) | |
2313 { | |
2314 clonedSink.Add(anEvent); | |
2315 } | |
2316 | |
2317 foreach(IVsHierarchyEvents clonedEvent in cloned
Sink) | |
2318 { | |
2319 int result = clonedEvent.OnItemDeleted(t
his.hierarchyId); | |
2320 if(ErrorHandler.Failed(result) && result
!= VSConstants.E_NOTIMPL) | |
2321 { | |
2322 ErrorHandler.ThrowOnFailure(resu
lt); | |
2323 } | |
2324 } | |
2325 } | |
2326 } | |
2327 | |
2328 public void OnItemsAppended(HierarchyNode parent) | |
2329 { | |
2330 if(parent == null) | |
2331 { | |
2332 throw new ArgumentNullException("parent"); | |
2333 } | |
2334 | |
2335 HierarchyNode foo; | |
2336 foo = this.projectMgr == null ? this : this.projectMgr; | |
2337 | |
2338 if(foo == this.projectMgr && (this.projectMgr.EventTrigg
eringFlag & ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents) != 0) | |
2339 { | |
2340 return; | |
2341 } | |
2342 | |
2343 foreach(IVsHierarchyEvents sink in foo.hierarchyEventSin
ks) | |
2344 { | |
2345 int result = sink.OnItemsAppended(parent.hierarc
hyId); | |
2346 | |
2347 if(ErrorHandler.Failed(result) && result != VSCo
nstants.E_NOTIMPL) | |
2348 { | |
2349 ErrorHandler.ThrowOnFailure(result); | |
2350 } | |
2351 } | |
2352 } | |
2353 | |
2354 | |
2355 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "propid")] | |
2356 public void OnPropertyChanged(HierarchyNode node, int propid, ui
nt flags) | |
2357 { | |
2358 if(node == null) | |
2359 { | |
2360 throw new ArgumentNullException("node"); | |
2361 } | |
2362 HierarchyNode foo; | |
2363 foo = this.projectMgr == null ? this : this.projectMgr; | |
2364 if(foo == this.projectMgr && (this.projectMgr.EventTrigg
eringFlag & ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents) != 0) | |
2365 { | |
2366 return; | |
2367 } | |
2368 | |
2369 foreach(IVsHierarchyEvents sink in foo.hierarchyEventSin
ks) | |
2370 { | |
2371 int result = sink.OnPropertyChanged(node.hierarc
hyId, propid, flags); | |
2372 | |
2373 if(ErrorHandler.Failed(result) && result != VSCo
nstants.E_NOTIMPL) | |
2374 { | |
2375 ErrorHandler.ThrowOnFailure(result); | |
2376 } | |
2377 } | |
2378 } | |
2379 | |
2380 | |
2381 public void OnInvalidateItems(HierarchyNode parent) | |
2382 { | |
2383 if(parent == null) | |
2384 { | |
2385 throw new ArgumentNullException("parent"); | |
2386 } | |
2387 HierarchyNode foo; | |
2388 foo = this.projectMgr == null ? this : this.projectMgr; | |
2389 if(foo == this.projectMgr && (this.projectMgr.EventTrigg
eringFlag & ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents) != 0) | |
2390 { | |
2391 return; | |
2392 } | |
2393 | |
2394 foreach(IVsHierarchyEvents sink in foo.hierarchyEventSin
ks) | |
2395 { | |
2396 int result = sink.OnInvalidateItems(parent.hiera
rchyId); | |
2397 | |
2398 if(ErrorHandler.Failed(result) && result != VSCo
nstants.E_NOTIMPL) | |
2399 { | |
2400 ErrorHandler.ThrowOnFailure(result); | |
2401 } | |
2402 } | |
2403 } | |
2404 | |
2405 /// <summary> | |
2406 /// Causes the hierarchy to be redrawn. | |
2407 /// </summary> | |
2408 /// <param name="element">Used by the hierarchy to decide which
element to redraw</param> | |
2409 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBe
CasedCorrectly", MessageId = "Re")] | |
2410 [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShould
BeCasedCorrectly", MessageId = "ReDraw")] | |
2411 public virtual void ReDraw(UIHierarchyElement element) | |
2412 { | |
2413 | |
2414 foreach(IVsHierarchyEvents sink in this.projectMgr.hiera
rchyEventSinks) | |
2415 { | |
2416 int result; | |
2417 if((element & UIHierarchyElement.Icon) != 0) | |
2418 { | |
2419 result = sink.OnPropertyChanged(this.ID,
(int)__VSHPROPID.VSHPROPID_IconIndex, 0); | |
2420 Debug.Assert(ErrorHandler.Succeeded(resu
lt), "Redraw failed for node " + this.GetMkDocument()); | |
2421 } | |
2422 | |
2423 if((element & UIHierarchyElement.Caption) != 0) | |
2424 { | |
2425 result = sink.OnPropertyChanged(this.ID,
(int)__VSHPROPID.VSHPROPID_Caption, 0); | |
2426 Debug.Assert(ErrorHandler.Succeeded(resu
lt), "Redraw failed for node " + this.GetMkDocument()); | |
2427 } | |
2428 | |
2429 if((element & UIHierarchyElement.SccState) != 0) | |
2430 { | |
2431 result = sink.OnPropertyChanged(this.ID,
(int)__VSHPROPID.VSHPROPID_StateIconIndex, 0); | |
2432 Debug.Assert(ErrorHandler.Succeeded(resu
lt), "Redraw failed for node " + this.GetMkDocument()); | |
2433 } | |
2434 } | |
2435 | |
2436 } | |
2437 | |
2438 /// <summary> | |
2439 /// Finds a non virtual hierarchy item by its project element. | |
2440 /// </summary> | |
2441 /// <param name="node">The Project element to find</param> | |
2442 /// <returns>The node found</returns> | |
2443 public HierarchyNode FindChildByProjectElement(ProjectElement no
de) | |
2444 { | |
2445 if(node == null) | |
2446 { | |
2447 throw new ArgumentNullException("node"); | |
2448 } | |
2449 | |
2450 for(HierarchyNode child = this.FirstChild; child != null
; child = child.NextSibling) | |
2451 { | |
2452 if(!child.ItemNode.IsVirtual && child.ItemNode =
= node) | |
2453 { | |
2454 return child; | |
2455 } | |
2456 } | |
2457 return null; | |
2458 } | |
2459 | |
2460 public object GetService(Type type) | |
2461 { | |
2462 if(type == null) | |
2463 { | |
2464 throw new ArgumentNullException("type"); | |
2465 } | |
2466 | |
2467 if(this.projectMgr.Site == null) return null; | |
2468 return this.projectMgr.Site.GetService(type); | |
2469 } | |
2470 | |
2471 | |
2472 #endregion | |
2473 | |
2474 #region IDisposable | |
2475 /// <summary> | |
2476 /// The IDispose interface Dispose method for disposing the obje
ct determinastically. | |
2477 /// </summary> | |
2478 public void Dispose() | |
2479 { | |
2480 this.Dispose(true); | |
2481 GC.SuppressFinalize(this); | |
2482 } | |
2483 | |
2484 #endregion | |
2485 | |
2486 #region IVsHierarchy methods | |
2487 | |
2488 public virtual int AdviseHierarchyEvents(IVsHierarchyEvents sink
, out uint cookie) | |
2489 { | |
2490 cookie = this.hierarchyEventSinks.Add(sink) + 1; | |
2491 return VSConstants.S_OK; | |
2492 } | |
2493 | |
2494 | |
2495 public virtual int Close() | |
2496 { | |
2497 DocumentManager manager = this.GetDocumentManager(); | |
2498 try | |
2499 { | |
2500 if(manager != null) | |
2501 { | |
2502 manager.Close(__FRAMECLOSE.FRAMECLOSE_Pr
omptSave); | |
2503 } | |
2504 | |
2505 } | |
2506 catch { } | |
2507 finally | |
2508 { | |
2509 this.Dispose(true); | |
2510 } | |
2511 | |
2512 return VSConstants.S_OK; | |
2513 } | |
2514 | |
2515 | |
2516 public virtual int GetCanonicalName(uint itemId, out string name
) | |
2517 { | |
2518 HierarchyNode n = this.projectMgr.NodeFromItemId(itemId)
; | |
2519 name = (n != null) ? n.GetCanonicalName() : null; | |
2520 return VSConstants.S_OK; | |
2521 } | |
2522 | |
2523 | |
2524 public virtual int GetGuidProperty(uint itemId, int propid, out
Guid guid) | |
2525 { | |
2526 guid = Guid.Empty; | |
2527 HierarchyNode n = this.projectMgr.NodeFromItemId(itemId)
; | |
2528 if(n != null) | |
2529 { | |
2530 int hr = n.GetGuidProperty(propid, out guid); | |
2531 __VSHPROPID vspropId = (__VSHPROPID)propid; | |
2532 CCITracing.TraceCall(vspropId.ToString() + "=" +
guid.ToString()); | |
2533 return hr; | |
2534 } | |
2535 if(guid == Guid.Empty) | |
2536 { | |
2537 return VSConstants.DISP_E_MEMBERNOTFOUND; | |
2538 } | |
2539 return VSConstants.S_OK; | |
2540 } | |
2541 | |
2542 | |
2543 public virtual int GetProperty(uint itemId, int propId, out obje
ct propVal) | |
2544 { | |
2545 propVal = null; | |
2546 if(itemId != VSConstants.VSITEMID_ROOT && propId == (int
)__VSHPROPID.VSHPROPID_IconImgList) | |
2547 { | |
2548 return VSConstants.DISP_E_MEMBERNOTFOUND; | |
2549 } | |
2550 | |
2551 | |
2552 HierarchyNode n = this.projectMgr.NodeFromItemId(itemId)
; | |
2553 if(n != null) | |
2554 { | |
2555 propVal = n.GetProperty(propId); | |
2556 } | |
2557 if(propVal == null) | |
2558 { | |
2559 return VSConstants.DISP_E_MEMBERNOTFOUND; | |
2560 } | |
2561 return VSConstants.S_OK; | |
2562 } | |
2563 | |
2564 | |
2565 public virtual int GetNestedHierarchy(uint itemId, ref Guid iidH
ierarchyNested, out IntPtr ppHierarchyNested, out uint pItemId) | |
2566 { | |
2567 ppHierarchyNested = IntPtr.Zero; | |
2568 pItemId = 0; | |
2569 // If itemid is not a nested hierarchy we must return E_
FAIL. | |
2570 return VSConstants.E_FAIL; | |
2571 } | |
2572 | |
2573 | |
2574 public virtual int GetSite(out Microsoft.VisualStudio.OLE.Intero
p.IServiceProvider site) | |
2575 { | |
2576 site = this.projectMgr.Site.GetService(typeof(Microsoft.
VisualStudio.OLE.Interop.IServiceProvider)) as Microsoft.VisualStudio.OLE.Intero
p.IServiceProvider; | |
2577 return VSConstants.S_OK; | |
2578 } | |
2579 | |
2580 | |
2581 /// <summary> | |
2582 /// the canonicalName of an item is it's URL, or better phrased, | |
2583 /// the persistence data we put into @RelPath, which is a relati
ve URL | |
2584 /// to the root project | |
2585 /// returning the itemID from this means scanning the list | |
2586 /// </summary> | |
2587 /// <param name="name"></param> | |
2588 /// <param name="itemId"></param> | |
2589 public virtual int ParseCanonicalName(string name, out uint item
Id) | |
2590 { | |
2591 // we always start at the current node and go it's child
ren down, so | |
2592 // if you want to scan the whole tree, better call | |
2593 // the root | |
2594 itemId = 0; | |
2595 | |
2596 // The default implemenation will check for case insensi
tive comparision. | |
2597 if(String.Compare(name, this.Url, StringComparison.Ordin
alIgnoreCase) == 0) | |
2598 { | |
2599 itemId = this.hierarchyId; | |
2600 return VSConstants.S_OK; | |
2601 } | |
2602 if(itemId == 0 && this.firstChild != null) | |
2603 { | |
2604 ErrorHandler.ThrowOnFailure(this.firstChild.Pars
eCanonicalName(name, out itemId)); | |
2605 } | |
2606 if(itemId == 0 && this.nextSibling != null) | |
2607 { | |
2608 ErrorHandler.ThrowOnFailure(this.nextSibling.Par
seCanonicalName(name, out itemId)); | |
2609 } | |
2610 return VSConstants.S_OK; | |
2611 } | |
2612 | |
2613 | |
2614 public virtual int QueryClose(out int fCanClose) | |
2615 { | |
2616 fCanClose = 1; | |
2617 return VSConstants.S_OK; | |
2618 } | |
2619 | |
2620 | |
2621 public virtual int SetGuidProperty(uint itemId, int propid, ref
Guid guid) | |
2622 { | |
2623 HierarchyNode n = this.projectMgr.NodeFromItemId(itemId)
; | |
2624 int rc = VSConstants.E_INVALIDARG; | |
2625 if(n != null) | |
2626 { | |
2627 rc = n.SetGuidProperty(propid, ref guid); | |
2628 } | |
2629 return rc; | |
2630 } | |
2631 | |
2632 | |
2633 public virtual int SetProperty(uint itemId, int propid, object v
alue) | |
2634 { | |
2635 HierarchyNode n = this.projectMgr.NodeFromItemId(itemId)
; | |
2636 if(n != null) | |
2637 { | |
2638 return n.SetProperty(propid, value); | |
2639 } | |
2640 else | |
2641 { | |
2642 return VSConstants.DISP_E_MEMBERNOTFOUND; | |
2643 } | |
2644 } | |
2645 | |
2646 | |
2647 public virtual int SetSite(Microsoft.VisualStudio.OLE.Interop.IS
erviceProvider site) | |
2648 { | |
2649 return VSConstants.E_NOTIMPL; | |
2650 } | |
2651 | |
2652 | |
2653 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usag
e", "CA2233:OperationsShouldNotOverflow", MessageId = "cookie-1")] | |
2654 public virtual int UnadviseHierarchyEvents(uint cookie) | |
2655 { | |
2656 this.hierarchyEventSinks.RemoveAt(cookie - 1); | |
2657 return VSConstants.S_OK; | |
2658 } | |
2659 | |
2660 | |
2661 public int Unused0() | |
2662 { | |
2663 return VSConstants.E_NOTIMPL; | |
2664 } | |
2665 | |
2666 | |
2667 public int Unused1() | |
2668 { | |
2669 return VSConstants.E_NOTIMPL; | |
2670 } | |
2671 | |
2672 | |
2673 public int Unused2() | |
2674 { | |
2675 return VSConstants.E_NOTIMPL; | |
2676 } | |
2677 | |
2678 | |
2679 public int Unused3() | |
2680 { | |
2681 return VSConstants.E_NOTIMPL; | |
2682 } | |
2683 | |
2684 | |
2685 public int Unused4() | |
2686 { | |
2687 return VSConstants.E_NOTIMPL; | |
2688 } | |
2689 #endregion | |
2690 | |
2691 #region IVsUIHierarchy methods | |
2692 | |
2693 public virtual int ExecCommand(uint itemId, ref Guid guidCmdGrou
p, uint nCmdId, uint nCmdExecOpt, IntPtr pvain, IntPtr p) | |
2694 { | |
2695 return this.InternalExecCommand(guidCmdGroup, nCmdId, nC
mdExecOpt, pvain, p, CommandOrigin.UiHierarchy); | |
2696 } | |
2697 | |
2698 public virtual int QueryStatusCommand(uint itemId, ref Guid guid
CmdGroup, uint cCmds, OLECMD[] cmds, IntPtr pCmdText) | |
2699 { | |
2700 return this.QueryStatusSelection(guidCmdGroup, cCmds, cm
ds, pCmdText, CommandOrigin.UiHierarchy); | |
2701 } | |
2702 #endregion | |
2703 | |
2704 #region IVsPersistHierarchyItem2 methods | |
2705 | |
2706 /// <summary> | |
2707 /// Determines whether the hierarchy item changed. | |
2708 /// </summary> | |
2709 /// <param name="itemId">Item identifier of the hierarchy item c
ontained in VSITEMID.</param> | |
2710 /// <param name="docData">Pointer to the IUnknown interface of t
he hierarchy item.</param> | |
2711 /// <param name="isDirty">true if the hierarchy item changed.</p
aram> | |
2712 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code. </returns> | |
2713 public virtual int IsItemDirty(uint itemId, IntPtr docData, out
int isDirty) | |
2714 { | |
2715 IVsPersistDocData pd = (IVsPersistDocData)Marshal.GetObj
ectForIUnknown(docData); | |
2716 return ErrorHandler.ThrowOnFailure(pd.IsDocDataDirty(out
isDirty)); | |
2717 } | |
2718 | |
2719 /// <summary> | |
2720 /// Saves the hierarchy item to disk. | |
2721 /// </summary> | |
2722 /// <param name="saveFlag">Flags whose values are taken from the
VSSAVEFLAGS enumeration.</param> | |
2723 /// <param name="silentSaveAsName">New filename when doing silen
t save as</param> | |
2724 /// <param name="itemid">Item identifier of the hierarchy item s
aved from VSITEMID.</param> | |
2725 /// <param name="docData">Item identifier of the hierarchy item
saved from VSITEMID.</param> | |
2726 /// <param name="cancelled">[out] true if the save action was ca
nceled.</param> | |
2727 /// <returns>[out] true if the save action was canceled.</return
s> | |
2728 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Main
tainability", "CA1502:AvoidExcessiveComplexity")] | |
2729 public virtual int SaveItem(VSSAVEFLAGS saveFlag, string silentS
aveAsName, uint itemid, IntPtr docData, out int cancelled) | |
2730 { | |
2731 cancelled = 0; | |
2732 | |
2733 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
2734 { | |
2735 return VSConstants.E_FAIL; | |
2736 } | |
2737 | |
2738 // Validate itemid | |
2739 if(itemid == VSConstants.VSITEMID_ROOT || itemid == VSCo
nstants.VSITEMID_SELECTION) | |
2740 { | |
2741 return VSConstants.E_INVALIDARG; | |
2742 } | |
2743 | |
2744 HierarchyNode node = this.ProjectMgr.NodeFromItemId(item
id); | |
2745 if(node == null) | |
2746 { | |
2747 return VSConstants.E_FAIL; | |
2748 } | |
2749 | |
2750 string existingFileMoniker = node.GetMkDocument(); | |
2751 | |
2752 // We can only perform save if the document is open | |
2753 if(docData == IntPtr.Zero) | |
2754 { | |
2755 string errorMessage = string.Format(CultureInfo.
CurrentCulture, SR.GetString(SR.CanNotSaveFileNotOpeneInEditor, CultureInfo.Curr
entUICulture), node.Url); | |
2756 throw new InvalidOperationException(errorMessage
); | |
2757 } | |
2758 | |
2759 string docNew = String.Empty; | |
2760 int returnCode = VSConstants.S_OK; | |
2761 IPersistFileFormat ff = null; | |
2762 IVsPersistDocData dd = null; | |
2763 IVsUIShell shell = this.projectMgr.Site.GetService(typeo
f(SVsUIShell)) as IVsUIShell; | |
2764 | |
2765 if(shell == null) | |
2766 { | |
2767 return VSConstants.E_FAIL; | |
2768 } | |
2769 | |
2770 try | |
2771 { | |
2772 //Save docdata object. | |
2773 //For the saveas action a dialog is show in orde
r to enter new location of file. | |
2774 //In case of a save action and the file is reado
nly a dialog is also shown | |
2775 //with a couple of options, SaveAs, Overwrite or
Cancel. | |
2776 ff = Marshal.GetObjectForIUnknown(docData) as IP
ersistFileFormat; | |
2777 if(ff == null) | |
2778 { | |
2779 return VSConstants.E_FAIL; | |
2780 } | |
2781 if(VSSAVEFLAGS.VSSAVE_SilentSave == saveFlag) | |
2782 { | |
2783 ErrorHandler.ThrowOnFailure(shell.SaveDo
cDataToFile(saveFlag, ff, silentSaveAsName, out docNew, out cancelled)); | |
2784 } | |
2785 else | |
2786 { | |
2787 dd = Marshal.GetObjectForIUnknown(docDat
a) as IVsPersistDocData; | |
2788 if(dd == null) | |
2789 { | |
2790 return VSConstants.E_FAIL; | |
2791 } | |
2792 ErrorHandler.ThrowOnFailure(dd.SaveDocDa
ta(saveFlag, out docNew, out cancelled)); | |
2793 } | |
2794 | |
2795 // We can be unloaded after the SaveDocData() ca
ll if the save caused a designer to add a file and this caused | |
2796 // the project file to be reloaded (QEQS caused
a newer version of the project file to be downloaded). So we check | |
2797 // here. | |
2798 if(this.ProjectMgr == null || this.ProjectMgr.Is
Closed) | |
2799 { | |
2800 cancelled = 1; | |
2801 return (int)OleConstants.OLECMDERR_E_CAN
CELED; | |
2802 } | |
2803 else | |
2804 { | |
2805 // if a SaveAs occurred we need to updat
e to the fact our item's name has changed. | |
2806 // this includes the following: | |
2807 // 1. call RenameDocument on the
RunningDocumentTable | |
2808 // 2. update the full path name f
or the item in our hierarchy | |
2809 // 3. a directory-based project m
ay need to transfer the open editor to the | |
2810 // MiscFiles project if th
e new file is saved outside of the project directory. | |
2811 // This is accomplished by
calling IVsExternalFilesManager::TransferDocument | |
2812 | |
2813 // we have three options for a saveas ac
tion to be performed | |
2814 // 1. the flag was set (the save as comm
and was triggered) | |
2815 // 2. a silent save specifying a new doc
ument name | |
2816 // 3. a save command was triggered but w
as not possible because the file has a read only attrib. Therefore | |
2817 // the user has chosen to do a save a
s in the dialog that showed up | |
2818 bool emptyOrSamePath = String.IsNullOrEm
pty(docNew) || NativeMethods.IsSamePath(existingFileMoniker, docNew); | |
2819 bool saveAs = ((saveFlag == VSSAVEFLAGS.
VSSAVE_SaveAs)) || | |
2820 ((saveFlag == VSSAVEFLAGS.VSSAVE
_SilentSave) && !emptyOrSamePath) || | |
2821 ((saveFlag == VSSAVEFLAGS.VSSAVE
_Save) && !emptyOrSamePath); | |
2822 | |
2823 if(saveAs) | |
2824 { | |
2825 returnCode = node.AfterSaveItemA
s(docData, docNew); | |
2826 | |
2827 // If it has been cancelled reco
ver the old name. | |
2828 if((returnCode == (int)OleConsta
nts.OLECMDERR_E_CANCELED || returnCode == VSConstants.E_ABORT)) | |
2829 { | |
2830 // Cleanup. | |
2831 this.DeleteFromStorage(d
ocNew); | |
2832 if(this is ProjectNode &
& File.Exists(docNew)) | |
2833 { | |
2834 File.Delete(docN
ew); | |
2835 } | |
2836 | |
2837 if(ff != null) | |
2838 { | |
2839 returnCode = she
ll.SaveDocDataToFile(VSSAVEFLAGS.VSSAVE_SilentSave, ff, existingFileMoniker, out
docNew, out cancelled); | |
2840 } | |
2841 } | |
2842 else if(returnCode != VSConstant
s.S_OK) | |
2843 { | |
2844 ErrorHandler.ThrowOnFail
ure(returnCode); | |
2845 } | |
2846 } | |
2847 } | |
2848 } | |
2849 catch(COMException e) | |
2850 { | |
2851 Trace.WriteLine("Exception :" + e.Message); | |
2852 returnCode = e.ErrorCode; | |
2853 | |
2854 // Try to recover | |
2855 if(ff != null) | |
2856 { | |
2857 ErrorHandler.ThrowOnFailure(shell.SaveDo
cDataToFile(VSSAVEFLAGS.VSSAVE_SilentSave, ff, existingFileMoniker, out docNew,
out cancelled)); | |
2858 } | |
2859 } | |
2860 | |
2861 return returnCode; | |
2862 } | |
2863 | |
2864 /// <summary> | |
2865 /// Flag indicating that changes to a file can be ignored when i
tem is saved or reloaded. | |
2866 /// </summary> | |
2867 /// <param name="itemId">Specifies the item id from VSITEMID.</p
aram> | |
2868 /// <param name="ignoreFlag">Flag indicating whether or not to i
gnore changes (1 to ignore, 0 to stop ignoring).</param> | |
2869 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code.</returns> | |
2870 public virtual int IgnoreItemFileChanges(uint itemId, int ignore
Flag) | |
2871 { | |
2872 #region precondition | |
2873 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
2874 { | |
2875 return VSConstants.E_FAIL; | |
2876 } | |
2877 #endregion | |
2878 | |
2879 HierarchyNode n = this.ProjectMgr.NodeFromItemId(itemId)
; | |
2880 if(n != null) | |
2881 { | |
2882 n.IgnoreItemFileChanges(ignoreFlag == 0 ? false
: true); | |
2883 } | |
2884 | |
2885 return VSConstants.S_OK; | |
2886 } | |
2887 | |
2888 /// <summary> | |
2889 /// Called to determine whether a project item is reloadable bef
ore calling ReloadItem. | |
2890 /// </summary> | |
2891 /// <param name="itemId">Item identifier of an item in the hiera
rchy. Valid values are VSITEMID_NIL, VSITEMID_ROOT and VSITEMID_SELECTION.</para
m> | |
2892 /// <param name="isReloadable">A flag indicating that the projec
t item is reloadable (1 for reloadable, 0 for non-reloadable).</param> | |
2893 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code. </returns> | |
2894 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBe
SpelledCorrectly", MessageId = "Reloadable")] | |
2895 public virtual int IsItemReloadable(uint itemId, out int isReloa
dable) | |
2896 { | |
2897 isReloadable = 0; | |
2898 | |
2899 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
2900 { | |
2901 return VSConstants.E_FAIL; | |
2902 } | |
2903 | |
2904 HierarchyNode n = this.ProjectMgr.NodeFromItemId(itemId)
; | |
2905 if(n != null) | |
2906 { | |
2907 isReloadable = (n.IsItemReloadable()) ? 1 : 0; | |
2908 } | |
2909 | |
2910 return VSConstants.S_OK; | |
2911 } | |
2912 | |
2913 /// <summary> | |
2914 /// Called to reload a project item. | |
2915 /// </summary> | |
2916 /// <param name="itemId">Specifies itemid from VSITEMID.</param> | |
2917 /// <param name="reserved">Reserved.</param> | |
2918 /// <returns>If the method succeeds, it returns S_OK. If it fail
s, it returns an error code. </returns> | |
2919 public virtual int ReloadItem(uint itemId, uint reserved) | |
2920 { | |
2921 #region precondition | |
2922 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
2923 { | |
2924 return VSConstants.E_FAIL; | |
2925 } | |
2926 #endregion | |
2927 | |
2928 HierarchyNode n = this.ProjectMgr.NodeFromItemId(itemId)
; | |
2929 if(n != null) | |
2930 { | |
2931 n.ReloadItem(reserved); | |
2932 } | |
2933 | |
2934 return VSConstants.S_OK; | |
2935 } | |
2936 #endregion | |
2937 | |
2938 #region IOleCommandTarget methods | |
2939 /// <summary> | |
2940 /// CommandTarget.Exec is called for most major operations if th
ey are NOT UI based. Otherwise IVSUInode::exec is called first | |
2941 /// </summary> | |
2942 public virtual int Exec(ref Guid guidCmdGroup, uint nCmdId, uint
nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) | |
2943 { | |
2944 return this.InternalExecCommand(guidCmdGroup, nCmdId, nC
mdExecOpt, pvaIn, pvaOut, CommandOrigin.OleCommandTarget); | |
2945 } | |
2946 | |
2947 /// <summary> | |
2948 /// Queries the object for the command status | |
2949 /// </summary> | |
2950 /// <remarks>we only support one command at a time, i.e. the fir
st member in the OLECMD array</remarks> | |
2951 public virtual int QueryStatus(ref Guid guidCmdGroup, uint cCmds
, OLECMD[] prgCmds, IntPtr pCmdText) | |
2952 { | |
2953 return this.QueryStatusSelection(guidCmdGroup, cCmds, pr
gCmds, pCmdText, CommandOrigin.OleCommandTarget); | |
2954 } | |
2955 #endregion | |
2956 | |
2957 #region IVsHierarchyDeleteHandler methods | |
2958 | |
2959 public virtual int DeleteItem(uint delItemOp, uint itemId) | |
2960 { | |
2961 if(itemId == VSConstants.VSITEMID_SELECTION) | |
2962 { | |
2963 return VSConstants.E_INVALIDARG; | |
2964 } | |
2965 | |
2966 HierarchyNode node = this.projectMgr.NodeFromItemId(item
Id); | |
2967 if(node != null) | |
2968 { | |
2969 node.Remove((delItemOp & (uint)__VSDELETEITEMOPE
RATION.DELITEMOP_DeleteFromStorage) != 0); | |
2970 return VSConstants.S_OK; | |
2971 } | |
2972 | |
2973 return VSConstants.E_FAIL; | |
2974 } | |
2975 | |
2976 | |
2977 public virtual int QueryDeleteItem(uint delItemOp, uint itemId,
out int candelete) | |
2978 { | |
2979 candelete = 0; | |
2980 if(itemId == VSConstants.VSITEMID_SELECTION) | |
2981 { | |
2982 return VSConstants.E_INVALIDARG; | |
2983 } | |
2984 | |
2985 if(this.ProjectMgr == null || this.ProjectMgr.IsClosed) | |
2986 { | |
2987 return VSConstants.E_FAIL; | |
2988 } | |
2989 | |
2990 // We ask the project what state it is. If he is a state
that should not allow delete then we return. | |
2991 if(this.ProjectMgr.IsCurrentStateASuppressCommandsMode()
) | |
2992 { | |
2993 return VSConstants.S_OK; | |
2994 } | |
2995 | |
2996 HierarchyNode node = this.projectMgr.NodeFromItemId(item
Id); | |
2997 | |
2998 if(node == null) | |
2999 { | |
3000 return VSConstants.E_FAIL; | |
3001 } | |
3002 | |
3003 // Ask the nodes if they can remove the item. | |
3004 bool canDeleteItem = node.CanDeleteItem((__VSDELETEITEMO
PERATION)delItemOp); | |
3005 if(canDeleteItem) | |
3006 { | |
3007 candelete = 1; | |
3008 } | |
3009 | |
3010 return VSConstants.S_OK; | |
3011 } | |
3012 #endregion | |
3013 | |
3014 #region IVsHierarchyDropDataSource2 methods | |
3015 | |
3016 public virtual int GetDropInfo(out uint pdwOKEffects, out Micros
oft.VisualStudio.OLE.Interop.IDataObject ppDataObject, out IDropSource ppDropSou
rce) | |
3017 { | |
3018 pdwOKEffects = (uint)DropEffect.None; | |
3019 ppDataObject = null; | |
3020 ppDropSource = null; | |
3021 return VSConstants.E_NOTIMPL; | |
3022 } | |
3023 | |
3024 public virtual int OnDropNotify(int fDropped, uint dwEffects) | |
3025 { | |
3026 return VSConstants.E_NOTIMPL; | |
3027 } | |
3028 | |
3029 public virtual int OnBeforeDropNotify(Microsoft.VisualStudio.OLE
.Interop.IDataObject pDataObject, uint dwEffect, out int fCancelDrop) | |
3030 { | |
3031 pDataObject = null; | |
3032 fCancelDrop = 0; | |
3033 return VSConstants.E_NOTIMPL; | |
3034 } | |
3035 #endregion | |
3036 | |
3037 #region IVsHierarchyDropDataTarget methods | |
3038 | |
3039 public virtual int DragEnter(Microsoft.VisualStudio.OLE.Interop.
IDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) | |
3040 { | |
3041 return VSConstants.E_NOTIMPL; | |
3042 } | |
3043 | |
3044 public virtual int DragLeave() | |
3045 { | |
3046 return VSConstants.E_NOTIMPL; | |
3047 } | |
3048 | |
3049 public virtual int DragOver(uint grfKeyState, uint itemid, ref u
int pdwEffect) | |
3050 { | |
3051 return VSConstants.E_NOTIMPL; | |
3052 } | |
3053 | |
3054 public virtual int Drop(Microsoft.VisualStudio.OLE.Interop.IData
Object pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) | |
3055 { | |
3056 return VSConstants.E_NOTIMPL; | |
3057 } | |
3058 #endregion | |
3059 | |
3060 #region helper methods | |
3061 internal HierarchyNode FindChild(string name) | |
3062 { | |
3063 if(String.IsNullOrEmpty(name)) | |
3064 { | |
3065 return null; | |
3066 } | |
3067 | |
3068 HierarchyNode result; | |
3069 for(HierarchyNode child = this.firstChild; child != null
; child = child.NextSibling) | |
3070 { | |
3071 if(!String.IsNullOrEmpty(child.VirtualNodeName)
&& String.Compare(child.VirtualNodeName, name, StringComparison.OrdinalIgnoreCas
e) == 0) | |
3072 { | |
3073 return child; | |
3074 } | |
3075 // If it is a foldernode then it has a virtual n
ame but we want to find folder nodes by the document moniker or url | |
3076 else if((String.IsNullOrEmpty(child.VirtualNodeN
ame) || (child is FolderNode)) && | |
3077 (NativeMethods.IsSamePath(child.
GetMkDocument(), name) || NativeMethods.IsSamePath(child.Url, name))) | |
3078 { | |
3079 return child; | |
3080 } | |
3081 | |
3082 result = child.FindChild(name); | |
3083 if(result != null) | |
3084 { | |
3085 return result; | |
3086 } | |
3087 } | |
3088 return null; | |
3089 } | |
3090 | |
3091 /// <summary> | |
3092 /// Recursively find all nodes of type T | |
3093 /// </summary> | |
3094 /// <typeparam name="T">The type of hierachy node being serched
for</typeparam> | |
3095 /// <param name="nodes">A list of nodes of type T</param> | |
3096 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Perf
ormance", "CA1811:AvoidUncalledPrivateCode")] | |
3097 internal void FindNodesOfType<T>(List<T> nodes) | |
3098 where T : HierarchyNode | |
3099 { | |
3100 for(HierarchyNode n = this.FirstChild; n != null; n = n.
NextSibling) | |
3101 { | |
3102 if(n is T) | |
3103 { | |
3104 T nodeAsT = (T)n; | |
3105 nodes.Add(nodeAsT); | |
3106 } | |
3107 | |
3108 n.FindNodesOfType<T>(nodes); | |
3109 } | |
3110 } | |
3111 | |
3112 /// <summary> | |
3113 /// Adds an item from a project refererence to target node. | |
3114 /// </summary> | |
3115 /// <param name="projectRef"></param> | |
3116 /// <param name="targetNode"></param> | |
3117 internal bool AddFileToNodeFromProjectReference(string projectRe
f, HierarchyNode targetNode) | |
3118 { | |
3119 if(String.IsNullOrEmpty(projectRef)) | |
3120 { | |
3121 throw new ArgumentException(SR.GetString(SR.Para
meterCannotBeNullOrEmpty, CultureInfo.CurrentUICulture), "projectRef"); | |
3122 } | |
3123 | |
3124 if(targetNode == null) | |
3125 { | |
3126 throw new ArgumentNullException("targetNode"); | |
3127 } | |
3128 | |
3129 IVsSolution solution = this.GetService(typeof(IVsSolutio
n)) as IVsSolution; | |
3130 if(solution == null) | |
3131 { | |
3132 throw new InvalidOperationException(); | |
3133 } | |
3134 | |
3135 uint itemidLoc; | |
3136 IVsHierarchy hierarchy; | |
3137 string str; | |
3138 VSUPDATEPROJREFREASON[] reason = new VSUPDATEPROJREFREAS
ON[1]; | |
3139 ErrorHandler.ThrowOnFailure(solution.GetItemOfProjref(pr
ojectRef, out hierarchy, out itemidLoc, out str, reason)); | |
3140 if(hierarchy == null) | |
3141 { | |
3142 throw new InvalidOperationException(); | |
3143 } | |
3144 | |
3145 // This will throw invalid cast exception if the hierrac
hy is not a project. | |
3146 IVsProject project = (IVsProject)hierarchy; | |
3147 | |
3148 string moniker; | |
3149 ErrorHandler.ThrowOnFailure(project.GetMkDocument(itemid
Loc, out moniker)); | |
3150 string[] files = new String[1] { moniker }; | |
3151 VSADDRESULT[] vsaddresult = new VSADDRESULT[1]; | |
3152 vsaddresult[0] = VSADDRESULT.ADDRESULT_Failure; | |
3153 int addResult = targetNode.ProjectMgr.AddItem(targetNode
.ID, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, 0, files, IntPtr.Zero, vsadd
result); | |
3154 if(addResult != VSConstants.S_OK && addResult != VSConst
ants.S_FALSE && addResult != (int)OleConstants.OLECMDERR_E_CANCELED) | |
3155 { | |
3156 ErrorHandler.ThrowOnFailure(addResult); | |
3157 return false; | |
3158 } | |
3159 return (vsaddresult[0] == VSADDRESULT.ADDRESULT_Success)
; | |
3160 } | |
3161 | |
3162 internal void InstantiateItemsDraggedOrCutOrCopiedList() | |
3163 { | |
3164 this.itemsDraggedOrCutOrCopied = new List<HierarchyNode>
(); | |
3165 } | |
3166 #endregion | |
3167 } | |
3168 } | |
OLD | NEW |