PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Tools/IronStudio/IronStudio/VisualStudio/Project/HierarchyNode.cs

http://github.com/IronLanguages/main
C# | 2008 lines | 1395 code | 229 blank | 384 comment | 265 complexity | e153a4817df2a5a660a7983afc61f827 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. * ***************************************************************************/
  14. using System;
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Diagnostics.CodeAnalysis;
  19. using System.Globalization;
  20. using System.IO;
  21. using System.Runtime.InteropServices;
  22. using System.Text;
  23. using Microsoft.VisualStudio;
  24. using Microsoft.VisualStudio.OLE.Interop;
  25. using Microsoft.VisualStudio.Shell;
  26. //#define CCI_TRACING
  27. using Microsoft.VisualStudio.Shell.Interop;
  28. using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants;
  29. using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants;
  30. using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID;
  31. using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID;
  32. namespace Microsoft.VisualStudio.Project
  33. {
  34. /// <summary>
  35. /// An object that deals with user interaction via a GUI in the form a hierarchy: a parent node with zero or more child nodes, each of which
  36. /// can itself be a hierarchy.
  37. /// </summary>
  38. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling"), CLSCompliant(false), ComVisible(true)]
  39. public abstract class HierarchyNode :
  40. IVsUIHierarchy,
  41. IVsPersistHierarchyItem2,
  42. Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget,
  43. IVsHierarchyDropDataSource2,
  44. IVsHierarchyDropDataSource,
  45. IVsHierarchyDropDataTarget,
  46. IVsHierarchyDeleteHandler,
  47. IDisposable
  48. //, IVsBuildStatusCallback
  49. {
  50. #region nested types
  51. /// <summary>
  52. /// DropEffect as defined in oleidl.h
  53. /// </summary>
  54. internal enum DropEffect
  55. {
  56. None,
  57. Copy = 1,
  58. Move = 2,
  59. Link = 4
  60. };
  61. #endregion
  62. #region Events
  63. internal event EventHandler<HierarchyNodeEventArgs> OnChildAdded
  64. {
  65. add { onChildAdded += value; }
  66. remove { onChildAdded -= value; }
  67. }
  68. internal event EventHandler<HierarchyNodeEventArgs> OnChildRemoved
  69. {
  70. add { onChildRemoved += value; }
  71. remove { onChildRemoved -= value; }
  72. }
  73. #endregion
  74. #region static/const fields
  75. public static readonly Guid SolutionExplorer = new Guid(EnvDTE.Constants.vsWindowKindSolutionExplorer);
  76. public const int NoImage = -1;
  77. #if DEBUG
  78. internal static int LastTracedProperty;
  79. #endif
  80. #endregion
  81. #region fields
  82. private EventSinkCollection hierarchyEventSinks = new EventSinkCollection();
  83. private ProjectNode projectMgr;
  84. private ProjectElement itemNode;
  85. private HierarchyNode parentNode;
  86. private HierarchyNode nextSibling;
  87. private HierarchyNode firstChild;
  88. private HierarchyNode lastChild;
  89. private bool isExpanded;
  90. private uint hierarchyId;
  91. private uint docCookie;
  92. private bool hasDesigner;
  93. private string virtualNodeName = String.Empty; // Only used by virtual nodes
  94. private IVsHierarchy parentHierarchy;
  95. private int parentHierarchyItemId;
  96. private NodeProperties nodeProperties;
  97. private OleServiceProvider oleServiceProvider = new OleServiceProvider();
  98. private bool excludeNodeFromScc;
  99. private EventHandler<HierarchyNodeEventArgs> onChildAdded;
  100. private EventHandler<HierarchyNodeEventArgs> onChildRemoved;
  101. private bool hasParentNodeNameRelation;
  102. private List<HierarchyNode> itemsDraggedOrCutOrCopied;
  103. private bool sourceDraggedOrCutOrCopied;
  104. /// <summary>
  105. /// Has the object been disposed.
  106. /// </summary>
  107. /// <devremark>We will not specify a property for isDisposed, rather it is expected that the a private flag is defined
  108. /// on all subclasses. We do not want get in a situation where the base class's dipose is not called because a child sets the flag through the property.</devremark>
  109. private bool isDisposed;
  110. #endregion
  111. #region abstract properties
  112. /// <summary>
  113. /// The URL of the node.
  114. /// </summary>
  115. /// <value></value>
  116. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]
  117. public abstract string Url
  118. {
  119. get;
  120. }
  121. /// <summary>
  122. /// The Caption of the node.
  123. /// </summary>
  124. /// <value></value>
  125. public abstract string Caption
  126. {
  127. get;
  128. }
  129. /// <summary>
  130. /// The item type guid associated to a node.
  131. /// </summary>
  132. /// <value></value>
  133. public abstract Guid ItemTypeGuid
  134. {
  135. get;
  136. }
  137. #endregion
  138. #region virtual properties
  139. /// <summary>
  140. /// Defines a string that is used to separate the name relation from the extension
  141. /// </summary>
  142. public virtual string NameRelationSeparator
  143. {
  144. get
  145. {
  146. return ".";
  147. }
  148. }
  149. public virtual int MenuCommandId
  150. {
  151. get { return VsMenus.IDM_VS_CTXT_NOCOMMANDS; }
  152. }
  153. /// <summary>
  154. /// Return an imageindex
  155. /// </summary>
  156. /// <returns></returns>
  157. public virtual int ImageIndex
  158. {
  159. get { return NoImage; }
  160. }
  161. /// <summary>
  162. /// Return an state icon index
  163. /// </summary>
  164. /// <returns></returns>
  165. /// <summary>
  166. /// Sets the state icon for a file.
  167. /// </summary>
  168. public virtual VsStateIcon StateIconIndex
  169. {
  170. get
  171. {
  172. if(!this.ExcludeNodeFromScc)
  173. {
  174. IVsSccManager2 sccManager = this.ProjectMgr.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2;
  175. if(sccManager != null)
  176. {
  177. VsStateIcon[] statIcons = new VsStateIcon[1] { VsStateIcon.STATEICON_NOSTATEICON };
  178. uint[] sccStatus = new uint[1] { 0 };
  179. // Get the glyph from the scc manager. Note that it will fail in command line
  180. // scenarios.
  181. if(ErrorHandler.Succeeded(sccManager.GetSccGlyph(1, new string[] { this.GetMkDocument() }, statIcons, sccStatus)))
  182. {
  183. return statIcons[0];
  184. }
  185. }
  186. }
  187. return VsStateIcon.STATEICON_NOSTATEICON;
  188. }
  189. }
  190. /// <summary>
  191. /// Defines whether a node can execute a command if in selection.
  192. /// </summary>
  193. public virtual bool CanExecuteCommand
  194. {
  195. get
  196. {
  197. return true;
  198. }
  199. }
  200. /// <summary>
  201. /// Used to determine the sort order of different node types
  202. /// in the solution explorer window.
  203. /// Nodes with the same priorities are sorted based on their captions.
  204. /// </summary>
  205. public virtual int SortPriority
  206. {
  207. get { return DefaultSortOrderNode.HierarchyNode; }
  208. }
  209. /// <summary>
  210. /// Defines the properties attached to this node.
  211. /// </summary>
  212. public virtual NodeProperties NodeProperties
  213. {
  214. get
  215. {
  216. if(null == nodeProperties)
  217. {
  218. nodeProperties = CreatePropertiesObject();
  219. }
  220. return this.nodeProperties;
  221. }
  222. }
  223. /// <summary>
  224. /// Returns an object that is a special view over this object; this is the value
  225. /// returned by the Object property of the automation objects.
  226. /// </summary>
  227. internal virtual object Object
  228. {
  229. get { return this; }
  230. }
  231. #endregion
  232. #region properties
  233. public OleServiceProvider OleServiceProvider
  234. {
  235. get
  236. {
  237. return this.oleServiceProvider;
  238. }
  239. }
  240. [System.ComponentModel.BrowsableAttribute(false)]
  241. public ProjectNode ProjectMgr
  242. {
  243. get
  244. {
  245. return this.projectMgr;
  246. }
  247. set
  248. {
  249. this.projectMgr = value;
  250. }
  251. }
  252. [System.ComponentModel.BrowsableAttribute(false)]
  253. public HierarchyNode NextSibling
  254. {
  255. get
  256. {
  257. return this.nextSibling;
  258. }
  259. set
  260. {
  261. this.nextSibling = value;
  262. }
  263. }
  264. [System.ComponentModel.BrowsableAttribute(false)]
  265. public HierarchyNode FirstChild
  266. {
  267. get
  268. {
  269. return this.firstChild;
  270. }
  271. set
  272. {
  273. this.firstChild = value;
  274. }
  275. }
  276. [System.ComponentModel.BrowsableAttribute(false)]
  277. public HierarchyNode LastChild
  278. {
  279. get
  280. {
  281. return this.lastChild;
  282. }
  283. set
  284. {
  285. this.lastChild = value;
  286. }
  287. }
  288. [System.ComponentModel.BrowsableAttribute(false)]
  289. public HierarchyNode Parent
  290. {
  291. get
  292. {
  293. return this.parentNode;
  294. }
  295. set
  296. {
  297. this.parentNode = value;
  298. }
  299. }
  300. [System.ComponentModel.BrowsableAttribute(false)]
  301. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID")]
  302. public uint ID
  303. {
  304. get
  305. {
  306. return this.hierarchyId;
  307. }
  308. internal set
  309. {
  310. this.hierarchyId = value;
  311. }
  312. }
  313. [System.ComponentModel.BrowsableAttribute(false)]
  314. public ProjectElement ItemNode
  315. {
  316. get
  317. {
  318. return itemNode;
  319. }
  320. set
  321. {
  322. itemNode = value;
  323. }
  324. }
  325. [System.ComponentModel.BrowsableAttribute(false)]
  326. public bool HasDesigner
  327. {
  328. get
  329. {
  330. return this.hasDesigner;
  331. }
  332. set { this.hasDesigner = value; }
  333. }
  334. [System.ComponentModel.BrowsableAttribute(false)]
  335. public bool IsExpanded
  336. {
  337. get
  338. {
  339. return this.isExpanded;
  340. }
  341. set { this.isExpanded = value; }
  342. }
  343. public string VirtualNodeName
  344. {
  345. get
  346. {
  347. return this.virtualNodeName;
  348. }
  349. set
  350. {
  351. this.virtualNodeName = value;
  352. }
  353. }
  354. [System.ComponentModel.BrowsableAttribute(false)]
  355. public HierarchyNode PreviousSibling
  356. {
  357. get
  358. {
  359. if(this.parentNode == null) return null;
  360. HierarchyNode prev = null;
  361. for(HierarchyNode child = this.parentNode.firstChild; child != null; child = child.nextSibling)
  362. {
  363. if(child == this)
  364. break;
  365. prev = child;
  366. }
  367. return prev;
  368. }
  369. }
  370. public uint DocCookie
  371. {
  372. get
  373. {
  374. return this.docCookie;
  375. }
  376. set
  377. {
  378. this.docCookie = value;
  379. }
  380. }
  381. /// <summary>
  382. /// Specifies if a Node is under source control.
  383. /// </summary>
  384. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Scc")]
  385. public bool ExcludeNodeFromScc
  386. {
  387. get
  388. {
  389. return this.excludeNodeFromScc;
  390. }
  391. set
  392. {
  393. this.excludeNodeFromScc = value;
  394. }
  395. }
  396. /// <summary>
  397. /// Defines if a node a name relation to its parent node
  398. ///
  399. /// </summary>
  400. public bool HasParentNodeNameRelation
  401. {
  402. get
  403. {
  404. return this.hasParentNodeNameRelation;
  405. }
  406. set
  407. {
  408. this.hasParentNodeNameRelation = value;
  409. }
  410. }
  411. protected bool SourceDraggedOrCutOrCopied
  412. {
  413. get
  414. {
  415. return this.sourceDraggedOrCutOrCopied;
  416. }
  417. set
  418. {
  419. this.sourceDraggedOrCutOrCopied = value;
  420. }
  421. }
  422. protected IList<HierarchyNode> ItemsDraggedOrCutOrCopied
  423. {
  424. get
  425. {
  426. return this.itemsDraggedOrCutOrCopied;
  427. }
  428. }
  429. #endregion
  430. #region ctors
  431. protected HierarchyNode()
  432. {
  433. this.IsExpanded = true;
  434. }
  435. protected HierarchyNode(ProjectNode root, ProjectElement element)
  436. {
  437. if (root == null)
  438. {
  439. throw new ArgumentNullException("root");
  440. }
  441. this.projectMgr = root;
  442. this.itemNode = element;
  443. this.hierarchyId = this.projectMgr.ItemIdMap.Add(this);
  444. this.oleServiceProvider.AddService(typeof(IVsHierarchy), root, false);
  445. }
  446. /// <summary>
  447. /// Overloaded ctor.
  448. /// </summary>
  449. /// <param name="root"></param>
  450. protected HierarchyNode(ProjectNode root)
  451. {
  452. if (root == null)
  453. {
  454. throw new ArgumentNullException("root");
  455. }
  456. this.projectMgr = root;
  457. this.itemNode = new ProjectElement(this.projectMgr, null, true);
  458. this.hierarchyId = this.projectMgr.ItemIdMap.Add(this);
  459. this.oleServiceProvider.AddService(typeof(IVsHierarchy), root, false);
  460. }
  461. #endregion
  462. #region static methods
  463. /// <summary>
  464. /// Get the outer IVsHierarchy implementation.
  465. /// This is used for scenario where a flavor may be modifying the behavior
  466. /// </summary>
  467. internal static IVsHierarchy GetOuterHierarchy(HierarchyNode node)
  468. {
  469. IVsHierarchy hierarchy = null;
  470. // The hierarchy of a node is its project node hierarchy
  471. IntPtr projectUnknown = Marshal.GetIUnknownForObject(node.projectMgr);
  472. try
  473. {
  474. hierarchy = (IVsHierarchy)Marshal.GetTypedObjectForIUnknown(projectUnknown, typeof(IVsHierarchy));
  475. }
  476. finally
  477. {
  478. if(projectUnknown != IntPtr.Zero)
  479. {
  480. Marshal.Release(projectUnknown);
  481. }
  482. }
  483. return hierarchy;
  484. }
  485. #endregion
  486. #region virtual methods
  487. /// <summary>
  488. /// Creates an object derived from NodeProperties that will be used to expose properties
  489. /// spacific for this object to the property browser.
  490. /// </summary>
  491. /// <returns></returns>
  492. protected virtual NodeProperties CreatePropertiesObject()
  493. {
  494. return null;
  495. }
  496. /// <summary>
  497. /// Return an iconhandle
  498. /// </summary>
  499. /// <param name="open"></param>
  500. /// <returns></returns>
  501. public virtual object GetIconHandle(bool open)
  502. {
  503. return null;
  504. }
  505. /// <summary>
  506. /// AddChild - add a node, sorted in the right location.
  507. /// </summary>
  508. /// <param name="node">The node to add.</param>
  509. public virtual void AddChild(HierarchyNode node)
  510. {
  511. if(node == null)
  512. {
  513. throw new ArgumentNullException("node");
  514. }
  515. // make sure the node is in the map.
  516. Object nodeWithSameID = this.projectMgr.ItemIdMap[node.hierarchyId];
  517. if(!Object.ReferenceEquals(node, nodeWithSameID as HierarchyNode))
  518. {
  519. if(nodeWithSameID == null && node.ID <= this.ProjectMgr.ItemIdMap.Count)
  520. { // reuse our hierarchy id if possible.
  521. this.projectMgr.ItemIdMap.SetAt(node.hierarchyId, this);
  522. }
  523. else
  524. {
  525. throw new InvalidOperationException();
  526. }
  527. }
  528. HierarchyNode previous = null;
  529. for(HierarchyNode n = this.firstChild; n != null; n = n.nextSibling)
  530. {
  531. if(this.ProjectMgr.CompareNodes(node, n) > 0) break;
  532. previous = n;
  533. }
  534. // insert "node" after "previous".
  535. if(previous != null)
  536. {
  537. node.nextSibling = previous.nextSibling;
  538. previous.nextSibling = node;
  539. if(previous == this.lastChild)
  540. {
  541. this.lastChild = node;
  542. }
  543. }
  544. else
  545. {
  546. if(this.lastChild == null)
  547. {
  548. this.lastChild = node;
  549. }
  550. node.nextSibling = this.firstChild;
  551. this.firstChild = node;
  552. }
  553. node.parentNode = this;
  554. this.OnItemAdded(this, node);
  555. }
  556. /// <summary>
  557. /// Removes a node from the hierarchy.
  558. /// </summary>
  559. /// <param name="node">The node to remove.</param>
  560. public virtual void RemoveChild(HierarchyNode node)
  561. {
  562. if(node == null)
  563. {
  564. throw new ArgumentNullException("node");
  565. }
  566. this.projectMgr.ItemIdMap.Remove(node);
  567. HierarchyNode last = null;
  568. for(HierarchyNode n = this.firstChild; n != null; n = n.nextSibling)
  569. {
  570. if(n == node)
  571. {
  572. if(last != null)
  573. {
  574. last.nextSibling = n.nextSibling;
  575. }
  576. if(n == this.lastChild)
  577. {
  578. if(last == this.lastChild)
  579. {
  580. this.lastChild = null;
  581. }
  582. else
  583. {
  584. this.lastChild = last;
  585. }
  586. }
  587. if(n == this.firstChild)
  588. {
  589. this.firstChild = n.nextSibling;
  590. }
  591. return;
  592. }
  593. last = n;
  594. }
  595. throw new InvalidOperationException("Node not found");
  596. }
  597. /// <summary>
  598. /// Returns an automation object representing this node
  599. /// </summary>
  600. /// <returns>The automation object</returns>
  601. public virtual object GetAutomationObject()
  602. {
  603. return new Automation.OAProjectItem<HierarchyNode>(this.projectMgr.GetAutomationObject() as Automation.OAProject, this);
  604. }
  605. /// <summary>
  606. /// Returns a property object based on a property id
  607. /// </summary>
  608. /// <param name="propId">the property id of the property requested</param>
  609. /// <returns>the property object requested</returns>
  610. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  611. public virtual object GetProperty(int propId)
  612. {
  613. object result = null;
  614. switch((__VSHPROPID)propId)
  615. {
  616. case __VSHPROPID.VSHPROPID_Expandable:
  617. result = (this.firstChild != null);
  618. break;
  619. case __VSHPROPID.VSHPROPID_Caption:
  620. result = this.Caption;
  621. break;
  622. case __VSHPROPID.VSHPROPID_Name:
  623. result = this.Caption;
  624. break;
  625. case __VSHPROPID.VSHPROPID_ExpandByDefault:
  626. result = false;
  627. break;
  628. case __VSHPROPID.VSHPROPID_IconImgList:
  629. result = this.ProjectMgr.ImageHandler.ImageList.Handle;
  630. break;
  631. case __VSHPROPID.VSHPROPID_OpenFolderIconIndex:
  632. case __VSHPROPID.VSHPROPID_IconIndex:
  633. int index = this.ImageIndex;
  634. if(index != NoImage)
  635. {
  636. result = index;
  637. }
  638. break;
  639. case __VSHPROPID.VSHPROPID_StateIconIndex:
  640. result = (int)this.StateIconIndex;
  641. break;
  642. case __VSHPROPID.VSHPROPID_IconHandle:
  643. result = GetIconHandle(false);
  644. break;
  645. case __VSHPROPID.VSHPROPID_OpenFolderIconHandle:
  646. result = GetIconHandle(true);
  647. break;
  648. case __VSHPROPID.VSHPROPID_NextVisibleSibling:
  649. goto case __VSHPROPID.VSHPROPID_NextSibling;
  650. case __VSHPROPID.VSHPROPID_NextSibling:
  651. result = (int)((this.nextSibling != null) ? this.nextSibling.hierarchyId : VSConstants.VSITEMID_NIL);
  652. break;
  653. case __VSHPROPID.VSHPROPID_FirstChild:
  654. goto case __VSHPROPID.VSHPROPID_FirstVisibleChild;
  655. case __VSHPROPID.VSHPROPID_FirstVisibleChild:
  656. result = (int)((this.firstChild != null) ? this.firstChild.hierarchyId : VSConstants.VSITEMID_NIL);
  657. break;
  658. case __VSHPROPID.VSHPROPID_Parent:
  659. if(null == this.parentNode)
  660. {
  661. unchecked { result = new IntPtr((int)VSConstants.VSITEMID_NIL); }
  662. }
  663. else
  664. {
  665. result = new IntPtr((int)this.parentNode.hierarchyId); // see bug 176470
  666. }
  667. break;
  668. case __VSHPROPID.VSHPROPID_ParentHierarchyItemid:
  669. if(parentHierarchy != null)
  670. {
  671. result = (IntPtr)parentHierarchyItemId; // VS requires VT_I4 | VT_INT_PTR
  672. }
  673. break;
  674. case __VSHPROPID.VSHPROPID_ParentHierarchy:
  675. result = parentHierarchy;
  676. break;
  677. case __VSHPROPID.VSHPROPID_Root:
  678. result = Marshal.GetIUnknownForObject(this.projectMgr);
  679. break;
  680. case __VSHPROPID.VSHPROPID_Expanded:
  681. result = this.isExpanded;
  682. break;
  683. case __VSHPROPID.VSHPROPID_BrowseObject:
  684. result = this.NodeProperties;
  685. if(result != null) result = new DispatchWrapper(result);
  686. break;
  687. case __VSHPROPID.VSHPROPID_EditLabel:
  688. if(this.ProjectMgr != null && !this.ProjectMgr.IsClosed && !this.ProjectMgr.IsCurrentStateASuppressCommandsMode())
  689. {
  690. result = GetEditLabel();
  691. }
  692. break;
  693. case __VSHPROPID.VSHPROPID_SaveName:
  694. //SaveName is the name shown in the Save and the Save Changes dialog boxes.
  695. result = this.Caption;
  696. break;
  697. case __VSHPROPID.VSHPROPID_ItemDocCookie:
  698. if(this.docCookie != 0) return (IntPtr)this.docCookie; //cast to IntPtr as some callers expect VT_INT
  699. break;
  700. case __VSHPROPID.VSHPROPID_ExtObject:
  701. result = GetAutomationObject();
  702. break;
  703. }
  704. __VSHPROPID2 id2 = (__VSHPROPID2)propId;
  705. switch(id2)
  706. {
  707. case __VSHPROPID2.VSHPROPID_NoDefaultNestedHierSorting:
  708. return true; // We are doing the sorting ourselves through VSHPROPID_FirstChild and VSHPROPID_NextSibling
  709. case __VSHPROPID2.VSHPROPID_BrowseObjectCATID:
  710. {
  711. // If there is a browse object and it is a NodeProperties, then get it's CATID
  712. object browseObject = this.GetProperty((int)__VSHPROPID.VSHPROPID_BrowseObject);
  713. if(browseObject != null)
  714. {
  715. if(browseObject is DispatchWrapper)
  716. browseObject = ((DispatchWrapper)browseObject).WrappedObject;
  717. result = this.ProjectMgr.GetCATIDForType(browseObject.GetType()).ToString("B");
  718. if(String.CompareOrdinal(result as string, Guid.Empty.ToString("B")) == 0)
  719. result = null;
  720. }
  721. break;
  722. }
  723. case __VSHPROPID2.VSHPROPID_ExtObjectCATID:
  724. {
  725. // If there is a extensibility object and it is a NodeProperties, then get it's CATID
  726. object extObject = this.GetProperty((int)__VSHPROPID.VSHPROPID_ExtObject);
  727. if(extObject != null)
  728. {
  729. if(extObject is DispatchWrapper)
  730. extObject = ((DispatchWrapper)extObject).WrappedObject;
  731. result = this.ProjectMgr.GetCATIDForType(extObject.GetType()).ToString("B");
  732. if(String.CompareOrdinal(result as string, Guid.Empty.ToString("B")) == 0)
  733. result = null;
  734. }
  735. break;
  736. }
  737. }
  738. #if DEBUG
  739. if(propId != LastTracedProperty)
  740. {
  741. string trailer = (result == null) ? "null" : result.ToString();
  742. CCITracing.TraceCall(this.hierarchyId + "," + propId.ToString() + " = " + trailer);
  743. LastTracedProperty = propId; // some basic filtering here...
  744. }
  745. #endif
  746. return result;
  747. }
  748. /// <summary>
  749. /// Sets the value of a property for a given property id
  750. /// </summary>
  751. /// <param name="propid">the property id of the property to be set</param>
  752. /// <param name="value">value of the property</param>
  753. /// <returns>S_OK if succeeded</returns>
  754. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "propid")]
  755. public virtual int SetProperty(int propid, object value)
  756. {
  757. __VSHPROPID id = (__VSHPROPID)propid;
  758. CCITracing.TraceCall(this.hierarchyId + "," + id.ToString());
  759. switch(id)
  760. {
  761. case __VSHPROPID.VSHPROPID_Expanded:
  762. this.isExpanded = (bool)value;
  763. break;
  764. case __VSHPROPID.VSHPROPID_ParentHierarchy:
  765. parentHierarchy = (IVsHierarchy)value;
  766. break;
  767. case __VSHPROPID.VSHPROPID_ParentHierarchyItemid:
  768. parentHierarchyItemId = (int)value;
  769. break;
  770. case __VSHPROPID.VSHPROPID_EditLabel:
  771. return SetEditLabel((string)value);
  772. default:
  773. CCITracing.TraceCall(" unhandled");
  774. break;
  775. }
  776. return VSConstants.S_OK;
  777. }
  778. /// <summary>
  779. /// Get a guid property
  780. /// </summary>
  781. /// <param name="propid">property id for the guid property requested</param>
  782. /// <param name="guid">the requested guid</param>
  783. /// <returns>S_OK if succeded</returns>
  784. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "propid")]
  785. public virtual int GetGuidProperty(int propid, out Guid guid)
  786. {
  787. guid = Guid.Empty;
  788. if(propid == (int)__VSHPROPID.VSHPROPID_TypeGuid)
  789. {
  790. guid = this.ItemTypeGuid;
  791. }
  792. if(guid.CompareTo(Guid.Empty) == 0)
  793. {
  794. return VSConstants.DISP_E_MEMBERNOTFOUND;
  795. }
  796. return VSConstants.S_OK;
  797. }
  798. /// <summary>
  799. /// Set a guid property.
  800. /// </summary>
  801. /// <param name="propid">property id of the guid property to be set</param>
  802. /// <param name="guid">the guid to be set</param>
  803. /// <returns>E_NOTIMPL</returns>
  804. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "propid")]
  805. public virtual int SetGuidProperty(int propid, ref Guid guid)
  806. {
  807. return VSConstants.E_NOTIMPL;
  808. }
  809. /// <summary>
  810. /// Called by the shell when a node has been renamed from the GUI
  811. /// </summary>
  812. /// <param name="label"></param>
  813. /// <returns>E_NOTIMPL</returns>
  814. public virtual int SetEditLabel(string label)
  815. {
  816. return VSConstants.E_NOTIMPL;
  817. }
  818. /// <summary>
  819. /// Called by the shell to get the node caption when the user tries to rename from the GUI
  820. /// </summary>
  821. /// <returns>the node cation</returns>
  822. public virtual string GetEditLabel()
  823. {
  824. return this.Caption;
  825. }
  826. /// <summary>
  827. /// This method is called by the interface method GetMkDocument to specify the item moniker.
  828. /// </summary>
  829. /// <returns>The moniker for this item</returns>
  830. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Mk")]
  831. public virtual string GetMkDocument()
  832. {
  833. return String.Empty;
  834. }
  835. /// <summary>
  836. /// Removes items from the hierarchy. Project overwrites this
  837. /// </summary>
  838. /// <param name="removeFromStorage"></param>
  839. public virtual void Remove(bool removeFromStorage)
  840. {
  841. string documentToRemove = this.GetMkDocument();
  842. // Ask Document tracker listeners if we can remove the item.
  843. string[] filesToBeDeleted = new string[1] { documentToRemove };
  844. VSQUERYREMOVEFILEFLAGS[] queryRemoveFlags = this.GetQueryRemoveFileFlags(filesToBeDeleted);
  845. if(!this.ProjectMgr.Tracker.CanRemoveItems(filesToBeDeleted, queryRemoveFlags))
  846. {
  847. return;
  848. }
  849. // Close the document if it has a manager.
  850. DocumentManager manager = this.GetDocumentManager();
  851. if(manager != null)
  852. {
  853. if(manager.Close(!removeFromStorage ? __FRAMECLOSE.FRAMECLOSE_PromptSave : __FRAMECLOSE.FRAMECLOSE_NoSave) == VSConstants.E_ABORT)
  854. {
  855. // User cancelled operation in message box.
  856. return;
  857. }
  858. }
  859. // Check out the project file.
  860. if(!this.ProjectMgr.QueryEditProjectFile(false))
  861. {
  862. throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
  863. }
  864. // Notify hierarchy event listeners that the file is going to be removed.
  865. OnItemDeleted();
  866. // Remove child if any before removing from the hierarchy
  867. for(HierarchyNode child = this.FirstChild; child != null; child = child.NextSibling)
  868. {
  869. child.Remove(removeFromStorage);
  870. }
  871. // the project node has no parentNode
  872. if(this.parentNode != null)
  873. {
  874. // Remove from the Hierarchy
  875. this.parentNode.RemoveChild(this);
  876. }
  877. // We save here the path to delete since this.Url might call the Include which will be deleted by the RemoveFromProjectFile call.
  878. string pathToDelete = this.GetMkDocument();
  879. this.itemNode.RemoveFromProjectFile();
  880. if(removeFromStorage)
  881. {
  882. this.DeleteFromStorage(pathToDelete);
  883. }
  884. // Close the document window if opened.
  885. CloseDocumentWindow(this);
  886. // Notify document tracker listeners that we have removed the item.
  887. VSREMOVEFILEFLAGS[] removeFlags = this.GetRemoveFileFlags(filesToBeDeleted);
  888. Debug.Assert(removeFlags != null, "At least an empty array should be returned for the GetRemoveFileFlags");
  889. this.ProjectMgr.Tracker.OnItemRemoved(documentToRemove, removeFlags[0]);
  890. // Notify hierarchy event listeners that we have removed the item
  891. if(null != this.parentNode.onChildRemoved)
  892. {
  893. HierarchyNodeEventArgs args = new HierarchyNodeEventArgs(this);
  894. parentNode.onChildRemoved(parentNode, args);
  895. }
  896. // Notify hierarchy event listeners that items have been invalidated
  897. OnInvalidateItems(this.parentNode);
  898. // Dispose the node now that is deleted.
  899. this.Dispose(true);
  900. }
  901. /// <summary>
  902. /// Returns the relational name which is defined as the first part of the caption until indexof NameRelationSeparator
  903. /// </summary>
  904. public virtual string GetRelationalName()
  905. {
  906. //Get the first part of the caption
  907. string[] partsOfParent = this.Caption.Split(new string[] { this.NameRelationSeparator }, StringSplitOptions.None);
  908. return partsOfParent[0];
  909. }
  910. /// <summary>
  911. /// Returns the 'extension' of the relational name
  912. /// e.g. form1.resx returns .resx, form1.designer.cs returns .designer.cs
  913. /// </summary>
  914. /// <returns>The extension</returns>
  915. public virtual string GetRelationNameExtension()
  916. {
  917. return this.Caption.Substring(this.Caption.IndexOf(this.NameRelationSeparator, StringComparison.Ordinal));
  918. }
  919. /// <summary>
  920. /// Close open document frame for a specific node.
  921. /// </summary>
  922. protected void CloseDocumentWindow(HierarchyNode node)
  923. {
  924. if (node == null)
  925. {
  926. throw new ArgumentNullException("node");
  927. }
  928. // We walk the RDT looking for all running documents attached to this hierarchy and itemid. There
  929. // are cases where there may be two different editors (not views) open on the same document.
  930. IEnumRunningDocuments pEnumRdt;
  931. IVsRunningDocumentTable pRdt = this.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
  932. if(pRdt == null)
  933. {
  934. throw new InvalidOperationException();
  935. }
  936. if(ErrorHandler.Succeeded(pRdt.GetRunningDocumentsEnum(out pEnumRdt)))
  937. {
  938. uint[] cookie = new uint[1];
  939. uint fetched;
  940. uint saveOptions = (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave;
  941. IVsHierarchy srpOurHier = node.projectMgr as IVsHierarchy;
  942. ErrorHandler.ThrowOnFailure(pEnumRdt.Reset());
  943. while(VSConstants.S_OK == pEnumRdt.Next(1, cookie, out fetched))
  944. {
  945. // Note we can pass NULL for all parameters we don't care about
  946. uint empty;
  947. string emptyStr;
  948. IntPtr ppunkDocData;
  949. IVsHierarchy srpHier;
  950. uint itemid = VSConstants.VSITEMID_NIL;
  951. ErrorHandler.ThrowOnFailure(pRdt.GetDocumentInfo(
  952. cookie[0],
  953. out empty,
  954. out empty,
  955. out empty,
  956. out emptyStr,
  957. out srpHier,
  958. out itemid,
  959. out ppunkDocData));
  960. // Is this one of our documents?
  961. if(Utilities.IsSameComObject(srpOurHier, srpHier) && itemid == node.ID)
  962. {
  963. IVsSolution soln = GetService(typeof(SVsSolution)) as IVsSolution;
  964. ErrorHandler.ThrowOnFailure(soln.CloseSolutionElement(saveOptions, srpOurHier, cookie[0]));
  965. }
  966. if(ppunkDocData != IntPtr.Zero)
  967. Marshal.Release(ppunkDocData);
  968. }
  969. }
  970. }
  971. /// <summary>
  972. /// Redraws the state icon if the node is not excluded from source control.
  973. /// </summary>
  974. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Scc")]
  975. protected internal virtual void UpdateSccStateIcons()
  976. {
  977. if(!this.ExcludeNodeFromScc)
  978. {
  979. this.ReDraw(UIHierarchyElement.SccState);
  980. }
  981. }
  982. /// <summary>
  983. /// To be overwritten by descendants.
  984. /// </summary>
  985. protected internal virtual int SetEditLabel(string label, string relativePath)
  986. {
  987. throw new NotImplementedException();
  988. }
  989. /// <summary>
  990. /// Called by the drag and drop implementation to ask the node
  991. /// which is being dragged/droped over which nodes should
  992. /// process the operation.
  993. /// This allows for dragging to a node that cannot contain
  994. /// items to let its parent accept the drop
  995. /// </summary>
  996. /// <returns>HierarchyNode that accept the drop handling</returns>
  997. protected internal virtual HierarchyNode GetDragTargetHandlerNode()
  998. {
  999. return this;
  1000. }
  1001. /// <summary>
  1002. /// Add a new Folder to the project hierarchy.
  1003. /// </summary>
  1004. /// <returns>S_OK if succeeded, otherwise an error</returns>
  1005. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  1006. protected virtual int AddNewFolder()
  1007. {
  1008. // Check out the project file.
  1009. if(!this.ProjectMgr.QueryEditProjectFile(false))
  1010. {
  1011. throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
  1012. }
  1013. try
  1014. {
  1015. // Generate a new folder name
  1016. string newFolderName;
  1017. ErrorHandler.ThrowOnFailure(this.projectMgr.GenerateUniqueItemName(this.hierarchyId, String.Empty, String.Empty, out newFolderName));
  1018. // create the project part of it, the project file
  1019. HierarchyNode child = this.ProjectMgr.CreateFolderNodes(Path.Combine(this.virtualNodeName, newFolderName));
  1020. if(child is FolderNode)
  1021. {
  1022. ((FolderNode)child).CreateDirectory();
  1023. }
  1024. // If we are in automation mode then skip the ui part which is about renaming the folder
  1025. if(!Utilities.IsInAutomationFunction(this.projectMgr.Site))
  1026. {
  1027. IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.projectMgr.Site, SolutionExplorer);
  1028. // we need to get into label edit mode now...
  1029. // so first select the new guy...
  1030. ErrorHandler.ThrowOnFailure(uiWindow.ExpandItem(this.projectMgr, child.hierarchyId, EXPANDFLAGS.EXPF_SelectItem));
  1031. // them post the rename command to the shell. Folder verification and creation will
  1032. // happen in the setlabel code...
  1033. IVsUIShell shell = this.projectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
  1034. Debug.Assert(shell != null, "Could not get the ui shell from the project");
  1035. if(shell == null)
  1036. {
  1037. return VSConstants.E_FAIL;
  1038. }
  1039. object dummy = null;
  1040. Guid cmdGroup = VsMenus.guidStandardCommandSet97;
  1041. ErrorHandler.ThrowOnFailure(shell.PostExecCommand(ref cmdGroup, (uint)VsCommands.Rename, 0, ref dummy));
  1042. }
  1043. }
  1044. catch(COMException e)
  1045. {
  1046. Trace.WriteLine("Exception : " + e.Message);
  1047. return e.ErrorCode;
  1048. }
  1049. return VSConstants.S_OK;
  1050. }
  1051. protected virtual int AddItemToHierarchy(HierarchyAddType addType)
  1052. {
  1053. CCITracing.TraceCall();
  1054. IVsAddProjectItemDlg addItemDialog;
  1055. string strFilter = String.Empty;
  1056. int iDontShowAgain;
  1057. uint uiFlags;
  1058. IVsProject3 project = (IVsProject3)this.projectMgr;
  1059. string strBrowseLocations = Path.GetDirectoryName(this.projectMgr.BaseURI.Uri.LocalPath);
  1060. System.Guid projectGuid = this.projectMgr.ProjectGuid;
  1061. addItemDialog = this.GetService(typeof(IVsAddProjectItemDlg)) as IVsAddProjectItemDlg;
  1062. if(addType == HierarchyAddType.AddNewItem)
  1063. uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddNewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSADDITEM_AllowHiddenTreeView);
  1064. else
  1065. uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddExistingItems | __VSADDITEMFLAGS.VSADDITEM_AllowMultiSelect | __VSADDITEMFLAGS.VSADDITEM_AllowStickyFilter);
  1066. ErrorHandler.ThrowOnFailure(addItemDialog.AddProjectItemDlg(this.hierarchyId, ref projectGuid, project, uiFlags, null, null, ref strBrowseLocations, ref strFilter, out iDontShowAgain)); /*&fDontShowAgain*/
  1067. return VSConstants.S_OK;
  1068. }
  1069. /// <summary>
  1070. /// Overwritten in subclasses
  1071. /// </summary>
  1072. protected virtual void DoDefaultAction()
  1073. {
  1074. CCITracing.TraceCall();
  1075. }
  1076. /// <summary>
  1077. /// Handles the exclude from project command.
  1078. /// </summary>
  1079. /// <returns></returns>
  1080. protected virtual int ExcludeFromProject()
  1081. {
  1082. Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr");
  1083. this.Remove(false);
  1084. return VSConstants.S_OK;
  1085. }
  1086. /// <summary>
  1087. /// Handles the Show in Designer command.
  1088. /// </summary>
  1089. /// <returns></returns>
  1090. protected virtual int ShowInDesigner(IList<HierarchyNode> selectedNodes)
  1091. {
  1092. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1093. }
  1094. /// <summary>
  1095. /// Prepares a selected node for clipboard.
  1096. /// It takes the the project reference string of this item and adds it to a stringbuilder.
  1097. /// </summary>
  1098. /// <returns>A stringbuilder.</returns>
  1099. /// <devremark>This method has to be public since seleceted nodes will call it.</devremark>
  1100. [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ClipBoard")]
  1101. protected internal virtual StringBuilder PrepareSelectedNodesForClipBoard()
  1102. {
  1103. Debug.Assert(this.ProjectMgr != null, " No project mananager available for this node " + ToString());
  1104. Debug.Assert(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null, " The itemsdragged list should have been initialized prior calling this method");
  1105. StringBuilder sb = new StringBuilder();
  1106. if(this.hierarchyId == VSConstants.VSITEMID_ROOT)
  1107. {
  1108. if(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null)
  1109. {
  1110. this.ProjectMgr.ItemsDraggedOrCutOrCopied.Clear();// abort
  1111. }
  1112. return sb;
  1113. }
  1114. if(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null)
  1115. {
  1116. this.ProjectMgr.ItemsDraggedOrCutOrCopied.Add(this);
  1117. }
  1118. string projref = String.Empty;
  1119. IVsSolution solution = this.GetService(typeof(IVsSolution)) as IVsSolution;
  1120. if(solution != null)
  1121. {
  1122. ErrorHandler.ThrowOnFailure(solution.GetProjrefOfItem(this.ProjectMgr, this.hierarchyId, out projref));
  1123. if(String.IsNullOrEmpty(projref))
  1124. {
  1125. if(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null)
  1126. {
  1127. this.ProjectMgr.ItemsDraggedOrCutOrCopied.Clear();// abort
  1128. }
  1129. return sb;
  1130. }
  1131. }
  1132. // Append the projectref and a null terminator to the string builder
  1133. sb.Append(projref);
  1134. sb.Append('\0');
  1135. return sb;
  1136. }
  1137. /// <summary>
  1138. /// Returns the Cannonical Name
  1139. /// </summary>
  1140. /// <returns>Cannonical Name</returns>
  1141. protected virtual string GetCanonicalName()
  1142. {
  1143. return this.GetMkDocument();
  1144. }
  1145. /// <summary>
  1146. /// Factory method for the Document Manager object
  1147. /// </summary>
  1148. /// <returns>null object, since a hierarchy node does not know its kind of document</returns>
  1149. /// <remarks>Must be overriden by derived node classes if a document manager is needed</remarks>
  1150. protected internal virtual DocumentManager GetDocumentManager()
  1151. {
  1152. return null;
  1153. }
  1154. /// <summary>
  1155. /// Displays the context menu.
  1156. /// </summary>
  1157. /// <param name="selectedNodes">list of selected nodes.</param>
  1158. /// <param name="pointerToVariant">contains the location (x,y) at which to show the menu.</param>
  1159. [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "pointer")]
  1160. protected virtual int DisplayContextMenu(IList<HierarchyNode> selectedNodes, IntPtr pointerToVariant)
  1161. {
  1162. if(selectedNodes == null || selectedNodes.Count == 0 || pointerToVariant == IntPtr.Zero)
  1163. {
  1164. return NativeMethods.OLECMDERR_E_NOTSUPPORTED;
  1165. }
  1166. int idmxStoredMenu = 0;
  1167. foreach(HierarchyNode node in selectedNodes)
  1168. {
  1169. // We check here whether we have a multiple selection of
  1170. // nodes of differing type.
  1171. if(idmxStoredMenu == 0)
  1172. {
  1173. // First time through or single node case
  1174. idmxStoredMenu = node.MenuCommandId;
  1175. }
  1176. else if(idmxStoredMenu != node.MenuCommandId)
  1177. {
  1178. // We have different node types. Check if any of the nodes is
  1179. // the project node and set the menu accordingly.
  1180. if(node.MenuCommandId == VsMenus.IDM_VS_CTXT_PROJNODE)
  1181. {
  1182. idmxStoredMenu = VsMenus.IDM_VS_CTXT_XPROJ_PROJITEM;
  1183. }
  1184. else
  1185. {
  1186. idmxStoredMenu = VsMenus.IDM_VS_CTXT_XPROJ_MULTIITEM;
  1187. }
  1188. }
  1189. }
  1190. object variant = Marshal.GetObjectForNativeVariant(pointerToVariant);
  1191. UInt32 pointsAsUint = (UInt32)variant;
  1192. short x = (short)(pointsAsUint & 0x0000ffff);
  1193. short y = (short)((pointsAsUint & 0xffff0000) / 0x10000);
  1194. POINTS points = new POINTS();
  1195. points.x = x;
  1196. points.y = y;
  1197. return ShowContextMenu(idmxStoredMenu, VsMenus.guidSHLMainMenu, points);
  1198. }
  1199. /// <summary>
  1200. /// Shows the specified context menu at a specified location.
  1201. /// </summary>
  1202. /// <param name="menuId">The context menu ID.</param>
  1203. /// <param name="groupGuid">The GUID of the menu group.</param>
  1204. /// <param name="points">The location at which to show the menu.</param>
  1205. protected virtual int ShowContextMenu(int menuId, Guid menuGroup, POINTS points)
  1206. {
  1207. IVsUIShell shell = this.projectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
  1208. Debug.Assert(shell != null, "Could not get the ui shell from the project");
  1209. if(shell == null)
  1210. {
  1211. return VSConstants.E_FAIL;
  1212. }
  1213. POINTS[] pnts = new POINTS[1];
  1214. pnts[0].x = points.x;
  1215. pnts[0].y = points.y;
  1216. return shell.ShowContextMenu(0, ref menuGroup, menuId, pnts, (Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget)this);
  1217. }
  1218. #region initiation of command execution
  1219. /// <summary>
  1220. /// Handles command execution.
  1221. /// </summary>
  1222. /// <param name="cmdGroup">Unique identifier of the command group</param>
  1223. /// <param name="cmd">The command to be executed.</param>
  1224. /// <param name="nCmdexecopt">Values describe how the object should execute the command.</param>
  1225. /// <param name="pvaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
  1226. /// <param name="pvaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
  1227. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1228. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cmdexecopt")]
  1229. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n")]
  1230. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "pva")]
  1231. protected virtual int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
  1232. {
  1233. if(this.projectMgr == null || this.projectMgr.IsClosed)
  1234. {
  1235. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1236. }
  1237. if(cmdGroup == Guid.Empty)
  1238. {
  1239. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1240. }
  1241. else if(cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds)
  1242. {
  1243. switch(cmd)
  1244. {
  1245. case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_DoubleClick:
  1246. case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_EnterKey:
  1247. this.DoDefaultAction();
  1248. return VSConstants.S_OK;
  1249. }
  1250. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1251. }
  1252. else if(cmdGroup == VsMenus.guidStandardCommandSet97)
  1253. {
  1254. HierarchyNode nodeToAddTo = this.GetDragTargetHandlerNode();
  1255. switch((VsCommands)cmd)
  1256. {
  1257. case VsCommands.AddNewItem:
  1258. return nodeToAddTo.AddItemToHierarchy(HierarchyAddType.AddNewItem);
  1259. case VsCommands.AddExistingItem:
  1260. return nodeToAddTo.AddItemToHierarchy(HierarchyAddType.AddExistingItem);
  1261. case VsCommands.NewFolder:
  1262. return nodeToAddTo.AddNewFolder();
  1263. case VsCommands.Paste:
  1264. return this.ProjectMgr.PasteFromClipboard(this);
  1265. }
  1266. }
  1267. else if(cmdGroup == VsMenus.guidStandardCommandSet2K)
  1268. {
  1269. switch((VsCommands2K)cmd)
  1270. {
  1271. case VsCommands2K.EXCLUDEFROMPROJECT:
  1272. return this.ExcludeFromProject();
  1273. }
  1274. }
  1275. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1276. }
  1277. /// <summary>
  1278. /// Executes a command that can only be executed once the whole selection is known.
  1279. /// </summary>
  1280. /// <param name="cmdGroup">Unique identifier of the command group</param>
  1281. /// <param name="cmdId">The command to be executed.</param>
  1282. /// <param name="cmdExecOpt">Values describe how the object should execute the command.</param>
  1283. /// <param name="vaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
  1284. /// <param name="vaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
  1285. /// <param name="commandOrigin">The origin of the command. From IOleCommandTarget or hierarchy.</param>
  1286. /// <param name="selectedNodes">The list of the selected nodes.</param>
  1287. /// <param name="handled">An out parameter specifying that the command was handled.</param>
  1288. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1289. [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "vaIn")]
  1290. protected virtual int ExecCommandThatDependsOnSelectedNodes(Guid cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin, IList<HierarchyNode> selectedNodes, out bool handled)
  1291. {
  1292. handled = false;
  1293. if(cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds)
  1294. {
  1295. switch(cmdId)
  1296. {
  1297. case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_RightClick:
  1298. // The UIHWCMDID_RightClick is what tells an IVsUIHierarchy in a UIHierarchyWindow
  1299. // to put up the context menu. Since the mouse may have moved between the
  1300. // mouse down and the mouse up, GetCursorPos won't tell you the right place
  1301. // to put the context menu (especially if it came through the keyboard).
  1302. // So we pack the proper menu position into pvaIn by
  1303. // memcpy'ing a POINTS struct into the VT_UI4 part of the pvaIn variant. The
  1304. // code to unpack it looks like this:
  1305. // ULONG ulPts = V_UI4(pvaIn);
  1306. // POINTS pts;
  1307. // memcpy((void*)&pts, &ulPts, sizeof(POINTS));
  1308. // You then pass that POINTS into DisplayContextMenu.
  1309. handled = true;
  1310. return this.DisplayContextMenu(selectedNodes, vaIn);
  1311. default:
  1312. break;
  1313. }
  1314. }
  1315. else if(cmdGroup == VsMenus.guidStandardCommandSet2K)
  1316. {
  1317. switch((VsCommands2K)cmdId)
  1318. {
  1319. case VsCommands2K.ViewInClassDiagram:
  1320. handled = true;
  1321. return this.ShowInDesigner(selectedNodes);
  1322. }
  1323. }
  1324. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1325. }
  1326. /// <summary>
  1327. /// Executes command that are independent of a selection.
  1328. /// </summary>
  1329. /// <param name="cmdGroup">Unique identifier of the command group</param>
  1330. /// <param name="cmdId">The command to be executed.</param>
  1331. /// <param name="cmdExecOpt">Values describe how the object should execute the command.</param>
  1332. /// <param name="vaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
  1333. /// <param name="vaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
  1334. /// <param name="commandOrigin">The origin of the command. From IOleCommandTarget or hierarchy.</param>
  1335. /// <param name="handled">An out parameter specifying that the command was handled.</param>
  1336. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1337. [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "vaIn")]
  1338. protected virtual int ExecCommandIndependentOfSelection(Guid cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin, out bool handled)
  1339. {
  1340. handled = false;
  1341. if(this.projectMgr == null || this.projectMgr.IsClosed)
  1342. {
  1343. return VSConstants.E_FAIL;
  1344. }
  1345. if(cmdGroup == VsMenus.guidStandardCommandSet97)
  1346. {
  1347. if(commandOrigin == CommandOrigin.OleCommandTarget)
  1348. {
  1349. switch((VsCommands)cmdId)
  1350. {
  1351. case VsCommands.Cut:
  1352. case VsCommands.Copy:
  1353. case VsCommands.Paste:
  1354. case VsCommands.Rename:
  1355. handled = true;
  1356. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1357. }
  1358. }
  1359. switch((VsCommands)cmdId)
  1360. {
  1361. case VsCommands.Copy:
  1362. handled = true;
  1363. return this.ProjectMgr.CopyToClipboard();
  1364. case VsCommands.Cut:
  1365. handled = true;
  1366. return this.ProjectMgr.CutToClipboard();
  1367. case VsCommands.SolutionCfg:
  1368. handled = true;
  1369. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1370. case VsCommands.SearchCombo:
  1371. handled = true;
  1372. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1373. }
  1374. }
  1375. else if(cmdGroup == VsMenus.guidStandardCommandSet2K)
  1376. {
  1377. // There should only be the project node who handles these and should manifest in the same action regardles of selection.
  1378. switch((VsCommands2K)cmdId)
  1379. {
  1380. case VsCommands2K.SHOWALLFILES:
  1381. handled = true;
  1382. return this.projectMgr.ShowAllFiles();
  1383. case VsCommands2K.ADDREFERENCE:
  1384. handled = true;
  1385. return this.projectMgr.AddProjectReference();
  1386. case VsCommands2K.ADDWEBREFERENCE:
  1387. handled = true;
  1388. return this.projectMgr.AddWebReference();
  1389. }
  1390. }
  1391. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1392. }
  1393. /// <summary>
  1394. /// The main entry point for command excection. Gets called from the IVsUIHierarchy and IOleCommandTarget methods.
  1395. /// </summary>
  1396. /// <param name="cmdGroup">Unique identifier of the command group</param>
  1397. /// <param name="cmdId">The command to be executed.</param>
  1398. /// <param name="cmdExecOpt">Values describe how the object should execute the command.</param>
  1399. /// <param name="vaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
  1400. /// <param name="vaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
  1401. /// <param name="commandOrigin">The origin of the command. From IOleCommandTarget or hierarchy.</param>
  1402. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1403. [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "vaIn")]
  1404. protected virtual int InternalExecCommand(Guid cmdGroup, uint cmdId, uint cmdExecOpt, IntPtr vaIn, IntPtr vaOut, CommandOrigin commandOrigin)
  1405. {
  1406. CCITracing.TraceCall(cmdGroup.ToString() + "," + cmdId.ToString());
  1407. if(this.projectMgr == null || this.projectMgr.IsClosed)
  1408. {
  1409. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1410. }
  1411. if(cmdGroup == Guid.Empty)
  1412. {
  1413. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1414. }
  1415. IList<HierarchyNode> selectedNodes = this.projectMgr.GetSelectedNodes();
  1416. // Check if all nodes can execute a command. If there is at least one that cannot return not handled.
  1417. foreach(HierarchyNode node in selectedNodes)
  1418. {
  1419. if(!node.CanExecuteCommand)
  1420. {
  1421. return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
  1422. }
  1423. }
  1424. // Handle commands that are …

Large files files are truncated, but you can click here to view the full file