Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 179 additions & 58 deletions Common/Product/SharedProject/ProjectNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ internal abstract partial class ProjectNode : HierarchyNode,
IBuildDependencyUpdate,
IVsProjectSpecialFiles,
IVsProjectBuildSystem,
IOleCommandTarget {
IOleCommandTarget,
IVsReferenceManagerUser {
#region nested types

#if DEV14_OR_LATER
Expand Down Expand Up @@ -1383,71 +1384,191 @@ public virtual VSADDRESULT RunWizard(HierarchyNode parentNode, string itemName,
}

/// <summary>
/// This overrides the base class method to show the VS 2005 style Add reference dialog. The ProjectNode implementation
/// shows the VS 2003 style Add Reference dialog.
/// Shows the Add Reference dialog.
/// </summary>
/// <returns>S_OK if succeeded. Failure other wise</returns>
public virtual int AddProjectReference() {
IVsComponentSelectorDlg2 componentDialog;
Guid guidEmpty = Guid.Empty;
VSCOMPONENTSELECTORTABINIT[] tabInit = new VSCOMPONENTSELECTORTABINIT[4];
string strBrowseLocations = Path.GetDirectoryName(ProjectHome);
/// <returns>S_OK if succeeded. Failure otherwise</returns>
public int AddProjectReference() {
var referenceManager = this.GetService(typeof(SVsReferenceManager)) as IVsReferenceManager;
if (referenceManager != null) {
var contextGuids = new[] {
VSConstants.ProjectReferenceProvider_Guid,
VSConstants.FileReferenceProvider_Guid
};
referenceManager.ShowReferenceManager(
this,
SR.GetString(SR.AddReferenceDialogTitle),
"VS.ReferenceManager",
contextGuids.First(),
false);
return VSConstants.S_OK;
} else {
return VSConstants.E_NOINTERFACE;
}
}

//Add the Project page
tabInit[0].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
// Tell the Add Reference dialog to call hierarchies GetProperty with the following
// propID to enable filtering out ourself from the Project to Project reference
tabInit[0].varTabInitInfo = (int)__VSHPROPID.VSHPROPID_ShowProjInSolutionPage;
tabInit[0].guidTab = VSConstants.GUID_SolutionPage;
#region IVsReferenceManagerUser Members

// Add the Browse for file page
tabInit[1].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
tabInit[1].guidTab = VSConstants.GUID_COMPlusPage;
tabInit[1].varTabInitInfo = 0;
void IVsReferenceManagerUser.ChangeReferences(uint operation, IVsReferenceProviderContext changedContext) {
var op = (__VSREFERENCECHANGEOPERATION)operation;
__VSREFERENCECHANGEOPERATIONRESULT result;

// Add the Browse for file page
tabInit[2].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
tabInit[2].guidTab = VSConstants.GUID_BrowseFilePage;
tabInit[2].varTabInitInfo = 0;
try {
if (op == __VSREFERENCECHANGEOPERATION.VSREFERENCECHANGEOPERATION_ADD) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to keep port the WebPI component picker over and keep it present?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, I'll keep WebPI out for this commit

result = this.AddReferences(changedContext);
} else {
result = this.RemoveReferences(changedContext);
}
} catch (InvalidOperationException e) {
Debug.Fail(e.ToString());
result = __VSREFERENCECHANGEOPERATIONRESULT.VSREFERENCECHANGEOPERATIONRESULT_DENY;
}

// Add the WebPI page
tabInit[3].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
tabInit[3].guidTab = typeof(WebPiComponentPickerControl).GUID;
tabInit[3].varTabInitInfo = 0;
if (result == __VSREFERENCECHANGEOPERATIONRESULT.VSREFERENCECHANGEOPERATIONRESULT_DENY) {
throw new InvalidOperationException();
}
}

uint pX = 0, pY = 0;
Array IVsReferenceManagerUser.GetProviderContexts() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this should call into a protected virtual version of this so subclasses can customize the available providers

return this.GetProviderContexts();
}

componentDialog = GetService(typeof(SVsComponentSelectorDlg)) as IVsComponentSelectorDlg2;
try {
// call the container to open the add reference dialog.
if (componentDialog != null) {
// Let the project know not to show itself in the Add Project Reference Dialog page
ShowProjectInSolutionPage = false;

// call the container to open the add reference dialog.
ErrorHandler.ThrowOnFailure(componentDialog.ComponentSelectorDlg2(
(System.UInt32)(__VSCOMPSELFLAGS.VSCOMSEL_MultiSelectMode | __VSCOMPSELFLAGS.VSCOMSEL_IgnoreMachineName),
(IVsComponentUser)this,
0,
null,
SR.GetString(SR.AddReferenceDialogTitle), // Title
"VS.AddReference", // Help topic
ref pX,
ref pY,
(uint)tabInit.Length,
tabInit,
ref guidEmpty,
AddReferenceExtensions.Replace('|', '\0') + "\0",
ref strBrowseLocations));
}
} catch (COMException e) {
Trace.WriteLine("Exception : " + e.Message);
return e.ErrorCode;
} finally {
// Let the project know it can show itself in the Add Project Reference Dialog page
ShowProjectInSolutionPage = true;
#endregion

protected virtual Array GetProviderContexts() {
var referenceManager = this.GetService(typeof(SVsReferenceManager)) as IVsReferenceManager;

var contextProviders = new[] {
CreateProjectReferenceProviderContext(referenceManager),
CreateFileReferenceProviderContext(referenceManager),
};

return contextProviders;
}

private IVsReferenceProviderContext CreateProjectReferenceProviderContext(IVsReferenceManager mgr) {
var context = mgr.CreateProviderContext(VSConstants.ProjectReferenceProvider_Guid) as IVsProjectReferenceProviderContext;
context.CurrentProject = this;

var referenceContainer = this.GetReferenceContainer();
var references = referenceContainer
.EnumReferences()
.OfType<ProjectReferenceNode>();
foreach (var reference in references) {
var newReference = context.CreateReference() as IVsProjectReference;
newReference.Identity = reference.ReferencedProjectGuid.ToString("B");
}
return VSConstants.S_OK;

return context as IVsReferenceProviderContext;
}

private IVsReferenceProviderContext CreateFileReferenceProviderContext(IVsReferenceManager mgr) {
var context = mgr.CreateProviderContext(VSConstants.FileReferenceProvider_Guid) as IVsFileReferenceProviderContext;

context.BrowseFilter = AddReferenceExtensions.Replace('|', '\0') + "\0";
return context as IVsReferenceProviderContext;
}

private __VSREFERENCECHANGEOPERATIONRESULT AddReferences(IVsReferenceProviderContext context) {
var addedReferences = this.GetAddedReferences(context);

var referenceContainer = this.GetReferenceContainer();
foreach (var selectorData in addedReferences) {
referenceContainer.AddReferenceFromSelectorData(selectorData);
}

return __VSREFERENCECHANGEOPERATIONRESULT.VSREFERENCECHANGEOPERATIONRESULT_ALLOW;
}

protected virtual IEnumerable<VSCOMPONENTSELECTORDATA> GetAddedReferences(IVsReferenceProviderContext context) {
var addedReferences = Enumerable.Empty<VSCOMPONENTSELECTORDATA>();

if (context.ProviderGuid == VSConstants.ProjectReferenceProvider_Guid) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These if checks should also be pulled into a protected virtual so that derived implementations can check for additional provider guids and then call the base class for the defaults

addedReferences = GetAddedReferences(context as IVsProjectReferenceProviderContext);
}
else if (context.ProviderGuid == VSConstants.FileReferenceProvider_Guid) {
addedReferences = GetAddedReferences(context as IVsFileReferenceProviderContext);
}

return addedReferences;
}

private __VSREFERENCECHANGEOPERATIONRESULT RemoveReferences(IVsReferenceProviderContext context) {
var removedReferences = this.GetRemovedReferences(context);

foreach (var refNode in removedReferences) {
refNode.Remove(true /* delete from storage*/);
}

return __VSREFERENCECHANGEOPERATIONRESULT.VSREFERENCECHANGEOPERATIONRESULT_ALLOW;
}

protected virtual IEnumerable<ReferenceNode> GetRemovedReferences(IVsReferenceProviderContext context) {
var removedReferences = Enumerable.Empty<ReferenceNode>();

if (context.ProviderGuid == VSConstants.ProjectReferenceProvider_Guid) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto on protected virtual

removedReferences = GetRemovedReferences(context as IVsProjectReferenceProviderContext);
}
else if (context.ProviderGuid == VSConstants.FileReferenceProvider_Guid) {
removedReferences = GetRemovedReferences(context as IVsFileReferenceProviderContext);
}

return removedReferences;
}

private IEnumerable<VSCOMPONENTSELECTORDATA> GetAddedReferences(IVsProjectReferenceProviderContext context) {
var selectedReferences = context
.References
.OfType<IVsProjectReference>()
.Select(reference => new VSCOMPONENTSELECTORDATA() {
type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Project,
bstrTitle = reference.Name,
bstrFile = new FileInfo(reference.FullPath).Directory.FullName,
bstrProjRef = reference.ReferenceSpecification,
});

return selectedReferences;
}

private IEnumerable<ReferenceNode> GetRemovedReferences(IVsProjectReferenceProviderContext context) {
var selectedReferences = context
.References
.OfType<IVsProjectReference>()
.Select(asmRef => new Guid(asmRef.Identity));

var referenceContainer = this.GetReferenceContainer();
var references = referenceContainer
.EnumReferences()
.OfType<ProjectReferenceNode>()
.Where(refNode => selectedReferences.Contains(refNode.ReferencedProjectGuid));

return references;
}

private IEnumerable<VSCOMPONENTSELECTORDATA> GetAddedReferences(IVsFileReferenceProviderContext context) {
var selectedReferences = context
.References
.OfType<IVsFileReference>()
.Select(reference => new VSCOMPONENTSELECTORDATA() {
type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_File,
bstrFile = reference.FullPath,
});

return selectedReferences;
}

private IEnumerable<ReferenceNode> GetRemovedReferences(IVsFileReferenceProviderContext context) {
var selectedReferences = context
.References
.OfType<IVsFileReference>()
.Select(fileRef => fileRef.FullPath);

var referenceContainer = this.GetReferenceContainer();
var references = referenceContainer
.EnumReferences()
.OfType<ReferenceNode>()
.Where(refNode => selectedReferences.Contains(refNode.Url));

return references;
}

protected virtual string AddReferenceExtensions {
Expand Down
2 changes: 1 addition & 1 deletion Common/Product/SharedProject/ProjectResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ Run Visual Studio with the /Log option and check ActivityLog.xml for more detail
{0}</value>
</data>
<data name="AddReferenceExtensions" xml:space="preserve">
<value>Dynamic Link Libraries (*.dll)|*.dll|All Files (*.*)|*.*</value>
<value>Component Files|*.winmd</value>
</data>
<data name="WebPiFeedError" xml:space="preserve">
<value>Unable to get feed "{0}".
Expand Down
3 changes: 3 additions & 0 deletions Nodejs/Product/Nodejs/Guids.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,8 @@ static class Guids {

public const string OfficeToolsBootstrapperCmdSetString = "{D26C976C-8EE8-4EC4-8746-F5F7702A17C5}";
public static readonly Guid OfficeToolsBootstrapperCmdSet = new Guid(OfficeToolsBootstrapperCmdSetString);

// UWP project flavor guid
public const string NodejsUwpProjectFlavor = "00251F00-BA30-4CE4-96A2-B8A1085F37AA";
};
}
14 changes: 13 additions & 1 deletion Nodejs/Product/Nodejs/Project/NodejsProjectNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,19 @@ internal override object Object {
}

protected override ReferenceContainerNode CreateReferenceContainerNode() {
return null;
// Only create a reference node if the project is targeting UWP
if(GetProjectTypeGuids().Contains(Guids.NodejsUwpProjectFlavor)) {
return base.CreateReferenceContainerNode();
} else {
return null;
}
}

private string GetProjectTypeGuids()
{
string projectTypeGuids = "";
ErrorHandler.ThrowOnFailure(((IVsAggregatableProject)this).GetAggregateProjectTypeGuids(out projectTypeGuids));
return projectTypeGuids;
}

public NodeModulesNode ModulesNode { get; private set; }
Expand Down