private IProjectTree CreateProjectItemTreeNode( IDependencyViewModel viewModel, IRule rule, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { ProjectTreeFlags flags = FilterFlags(viewModel.Flags, additionalFlags, excludedFlags); string filePath = (viewModel.OriginalModel != null && viewModel.OriginalModel.TopLevel && viewModel.OriginalModel.Resolved) ? viewModel.OriginalModel.GetTopLevelId() : viewModel.FilePath; var itemContext = ProjectPropertiesContext.GetContext( CommonServices.Project, file: filePath, itemType: viewModel.SchemaItemType, itemName: filePath); return(TreeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, propertySheet: null, browseObjectProperties: rule, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: flags)); }
/// <summary> /// Updates or creates new IProjectItemTree node /// </summary> private IProjectTree CreateOrUpdateProjectItemTreeNode( IProjectTree node, IDependencyViewModel viewModel, IRule rule, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node == null) { var flags = FilterFlags(viewModel.Flags, additionalFlags, excludedFlags); var itemContext = ProjectPropertiesContext.GetContext( CommonServices.Project, file: viewModel.FilePath, itemType: viewModel.SchemaItemType, itemName: viewModel.FilePath); node = TreeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, propertySheet: null, visible: true, browseObjectProperties: rule, flags: viewModel.Flags, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType()); } else { node = UpdateTreeNode(node, viewModel, rule); } return(node); }
public async Task <IRule> GetRuleAsync(IDependency dependency, IProjectCatalogSnapshot catalogs) { Requires.NotNull(dependency, nameof(dependency)); ConfiguredProject project = null; if (dependency.TargetFramework.Equals(TargetFramework.Any)) { project = ActiveConfiguredProject; } else { project = await DependenciesHost.GetConfiguredProject(dependency.TargetFramework) .ConfigureAwait(false) ?? ActiveConfiguredProject; } ConfiguredProjectExports configuredProjectExports = GetActiveConfiguredProjectExports(project); IImmutableDictionary <string, IPropertyPagesCatalog> namedCatalogs = await GetNamedCatalogsAsync(catalogs).ConfigureAwait(false); Requires.NotNull(namedCatalogs, nameof(namedCatalogs)); IPropertyPagesCatalog browseObjectsCatalog = namedCatalogs[PropertyPageContexts.BrowseObject]; Rule schema = browseObjectsCatalog.GetSchema(dependency.SchemaName); string itemSpec = string.IsNullOrEmpty(dependency.OriginalItemSpec) ? dependency.Path : dependency.OriginalItemSpec; var context = ProjectPropertiesContext.GetContext(UnconfiguredProject, itemType: dependency.SchemaItemType, itemName: itemSpec); IRule rule = null; if (schema != null) { if (dependency.Resolved) { rule = configuredProjectExports.RuleFactory.CreateResolvedReferencePageRule( schema, context, dependency.Name, dependency.Properties); } else { rule = browseObjectsCatalog.BindToContext(schema.Name, context); } } else { // Since we have no browse object, we still need to create *something* so // that standard property pages can pop up. Rule emptyRule = RuleExtensions.SynthesizeEmptyRule(context.ItemType); return(configuredProjectExports.PropertyPagesDataModelProvider.GetRule( emptyRule, context.File, context.ItemType, context.ItemName)); } return(rule); }
public async Task <IRule?> GetRuleAsync(IDependency dependency, IProjectCatalogSnapshot?catalogs) { Requires.NotNull(dependency, nameof(dependency)); ConfiguredProject project = dependency.TargetFramework.Equals(TargetFramework.Any) ? ActiveConfiguredProject : _dependenciesHost.GetConfiguredProject(dependency.TargetFramework) ?? ActiveConfiguredProject; IImmutableDictionary <string, IPropertyPagesCatalog> namedCatalogs = await GetNamedCatalogsAsync(); Requires.NotNull(namedCatalogs, nameof(namedCatalogs)); if (!namedCatalogs.TryGetValue(PropertyPageContexts.BrowseObject, out IPropertyPagesCatalog browseObjectsCatalog)) { // Issue https://github.com/dotnet/project-system/issues/4860 suggests this code path // can exist, however a repro was not found to dig deeper into the underlying cause. // For now just return null as the upstream caller handles null correctly anyway. return(null); } Rule schema = browseObjectsCatalog.GetSchema(dependency.SchemaName); string itemSpec = string.IsNullOrEmpty(dependency.OriginalItemSpec) ? dependency.Path : dependency.OriginalItemSpec; var context = ProjectPropertiesContext.GetContext(UnconfiguredProject, itemType: dependency.SchemaItemType, itemName: itemSpec); if (schema == null) { // Since we have no browse object, we still need to create *something* so // that standard property pages can pop up. Rule emptyRule = RuleExtensions.SynthesizeEmptyRule(context.ItemType); return(GetActiveConfiguredProjectExports(project).PropertyPagesDataModelProvider.GetRule( emptyRule, context.File, context.ItemType, context.ItemName)); } if (dependency.Resolved) { return(GetActiveConfiguredProjectExports(project).RuleFactory.CreateResolvedReferencePageRule( schema, context, dependency.Name, dependency.Properties)); } return(browseObjectsCatalog.BindToContext(schema.Name, context)); async Task <IImmutableDictionary <string, IPropertyPagesCatalog> > GetNamedCatalogsAsync() { if (catalogs != null) { return(catalogs.NamedCatalogs); } if (_namedCatalogs == null) { // Note: it is unlikely that we end up here, however for cases when node providers // getting their node data not from Design time build events, we might have OnDependenciesChanged // event coming before initial design time build event updates NamedCatalogs in this class. // Thus, just in case, explicitly request it here (GetCatalogsAsync will acquire a project read lock) _namedCatalogs = await ActiveConfiguredProject.Services .PropertyPagesCatalog .GetCatalogsAsync(CancellationToken.None); } return(_namedCatalogs); } }
private IProjectItemTree CreateProjectItemTreeNode(IProjectTree providerRootTreeNode, IDependencyNode nodeInfo, IProjectCatalogSnapshot catalogs) { var isGenericNodeType = nodeInfo.Flags.Contains(DependencyNode.GenericDependencyFlags); var properties = nodeInfo.Properties ?? ImmutableDictionary <string, string> .Empty .Add(Folder.IdentityProperty, nodeInfo.Caption) .Add(Folder.FullPathProperty, string.Empty); // For generic node types we do set correct, known item types, however for custom nodes // provided by third party extensions we can not guarantee that item type will be known. // Thus always set predefined itemType for all custom nodes. // TODO: generate specific xaml rule for generic Dependency nodes // tracking issue: https://github.com/dotnet/roslyn-project-system/issues/1102 var itemType = isGenericNodeType ? nodeInfo.Id.ItemType : Folder.SchemaName; // when itemSpec is not in valid absolute path format, property page does not show // item name correctly. Use real Name for the node here instead of caption, since caption // can have other info like version in it. var itemSpec = nodeInfo.Flags.Contains(DependencyNode.CustomItemSpec) ? nodeInfo.Name : nodeInfo.Id.ItemSpec; var itemContext = ProjectPropertiesContext.GetContext(UnconfiguredProject, itemType, itemSpec); var configuredProjectExports = GetActiveConfiguredProjectExports(ActiveConfiguredProject); IRule rule = null; if (nodeInfo.Resolved || !isGenericNodeType) { rule = GetRuleForResolvableReference( itemContext, new KeyValuePair <string, IImmutableDictionary <string, string> >( itemSpec, properties), catalogs, configuredProjectExports, isGenericNodeType); } else { rule = GetRuleForUnresolvableReference( itemContext, catalogs, configuredProjectExports); } // Notify about tree changes to customization context var customTreePropertyContext = GetCustomPropertyContext(providerRootTreeNode); var customTreePropertyValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = nodeInfo.Caption, Flags = nodeInfo.Flags, Icon = nodeInfo.Icon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(customTreePropertyContext, customTreePropertyValues); var treeItemNode = NewTree(caption: nodeInfo.Caption, item: itemContext, propertySheet: null, visible: true, browseObjectProperties: rule, flags: nodeInfo.Flags, icon: nodeInfo.Icon.ToProjectSystemType(), expandedIcon: nodeInfo.ExpandedIcon.ToProjectSystemType()); return(treeItemNode); }
private IProjectTree CreateOrUpdateNode( IProjectTree?node, IDependencyViewModel viewModel, IRule?browseObjectProperties, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } string?filePath = viewModel.OriginalModel != null && viewModel.OriginalModel.TopLevel && viewModel.OriginalModel.Resolved ? viewModel.OriginalModel.GetTopLevelId() : viewModel.FilePath; ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { // For IProjectTree remove ProjectTreeFlags.Common.Reference flag, otherwise CPS would fail to // map this node to graph node and GraphProvider would be never called. // Only IProjectItemTree can have this flag filteredFlags = filteredFlags.Except(DependencyTreeFlags.BaseReferenceFlags); return(_treeServices.CreateTree( caption: viewModel.Caption, filePath, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { Assumes.NotNull(filePath); var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: filePath, itemType: viewModel.SchemaItemType, itemName: filePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node !.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: browseObjectProperties, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }
/// <summary> /// Creates or updates a project tree for a given IProjectDependenciesSubTreeProvider /// </summary> /// <param name="dependenciesNode"></param> /// <param name="subTreeProvider"></param> /// <param name="changes"></param> /// <param name="catalogs">Can be null if sub tree provider does not use design time build</param> /// <param name="cancellationToken"></param> /// <returns>IProjectTree for root Dependencies node</returns> private IProjectTree CreateOrUpdateSubTreeProviderNode(IProjectTree dependenciesNode, IProjectDependenciesSubTreeProvider subTreeProvider, IDependenciesChangeDiff changes, IProjectCatalogSnapshot catalogs, CancellationToken cancellationToken) { Requires.NotNull(dependenciesNode, nameof(dependenciesNode)); Requires.NotNull(subTreeProvider, nameof(subTreeProvider)); Requires.NotNull(subTreeProvider.RootNode, nameof(subTreeProvider.RootNode)); Requires.NotNullOrEmpty(subTreeProvider.RootNode.Caption, nameof(subTreeProvider.RootNode.Caption)); Requires.NotNullOrEmpty(subTreeProvider.ProviderType, nameof(subTreeProvider.ProviderType)); var providerRootTreeNode = GetSubTreeRootNode(dependenciesNode, subTreeProvider.RootNode.Flags); if (subTreeProvider.RootNode.HasChildren || subTreeProvider.ShouldBeVisibleWhenEmpty) { bool newNode = false; if (providerRootTreeNode == null) { providerRootTreeNode = NewTree( caption: subTreeProvider.RootNode.Caption, visible: true, filePath: subTreeProvider.RootNode.Id.ToString(), browseObjectProperties: null, flags: subTreeProvider.RootNode.Flags, icon: subTreeProvider.RootNode.Icon.ToProjectSystemType(), expandedIcon: subTreeProvider.RootNode.ExpandedIcon.ToProjectSystemType()); newNode = true; } if (changes != null) { foreach (var removedItem in changes.RemovedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(removedItem.Id.ToString()); if (treeNode != null) { providerRootTreeNode = treeNode.Remove(); } } foreach (var updatedItem in changes.UpdatedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(updatedItem.Id.ToString()); if (treeNode != null) { var updatedNodeParentContext = GetCustomPropertyContext(treeNode.Parent); var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = updatedItem.Caption, Flags = updatedItem.Flags, Icon = updatedItem.Icon.ToProjectSystemType(), ExpandedIcon = updatedItem.ExpandedIcon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(updatedNodeParentContext, updatedValues); // update existing tree node properties treeNode = treeNode.SetProperties( caption: updatedItem.Caption, flags: updatedItem.Flags, icon: updatedItem.Icon.ToProjectSystemType(), expandedIcon: updatedItem.ExpandedIcon.ToProjectSystemType()); providerRootTreeNode = treeNode.Parent; } } var configuredProjectExports = GetActiveConfiguredProjectExports(ActiveConfiguredProject); foreach (var addedItem in changes.AddedNodes) { if (cancellationToken.IsCancellationRequested) { return(dependenciesNode); } var treeNode = providerRootTreeNode.FindNodeByPath(addedItem.Id.ToString()); if (treeNode == null) { IRule rule = null; if (addedItem.Properties != null) { // when itemSpec is not in valid absolute path format, property page does not show // item name correctly. var itemSpec = addedItem.Flags.Contains(DependencyNode.CustomItemSpec) ? addedItem.Caption : addedItem.Id.ItemSpec; var itemContext = ProjectPropertiesContext.GetContext(UnconfiguredProject, addedItem.Id.ItemType, itemSpec); if (addedItem.Resolved) { rule = GetRuleForResolvableReference( itemContext, new KeyValuePair <string, IImmutableDictionary <string, string> >( addedItem.Id.ItemSpec, addedItem.Properties), catalogs, configuredProjectExports); } else { rule = GetRuleForUnresolvableReference( itemContext, catalogs, configuredProjectExports); } } // Notify about tree changes to customization context var customTreePropertyContext = GetCustomPropertyContext(providerRootTreeNode); var customTreePropertyValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = addedItem.Caption, Flags = addedItem.Flags, Icon = addedItem.Icon.ToProjectSystemType() }; ApplyProjectTreePropertiesCustomization(customTreePropertyContext, customTreePropertyValues); treeNode = NewTree(caption: addedItem.Caption, visible: true, filePath: addedItem.Id.ToString(), browseObjectProperties: rule, flags: addedItem.Flags, icon: addedItem.Icon.ToProjectSystemType(), expandedIcon: addedItem.ExpandedIcon.ToProjectSystemType()); providerRootTreeNode = providerRootTreeNode.Add(treeNode).Parent; } } } if (newNode) { dependenciesNode = dependenciesNode.Add(providerRootTreeNode).Parent; } else { dependenciesNode = providerRootTreeNode.Parent; } } else { if (providerRootTreeNode != null) { dependenciesNode = dependenciesNode.Remove(providerRootTreeNode); } } return(dependenciesNode); }
private IProjectTree CreateOrUpdateNode( IProjectTree?node, IDependencyViewModel viewModel, IRule?browseObjectProperties, bool isProjectItem, ProjectTreeFlags?additionalFlags = null, ProjectTreeFlags?excludedFlags = null) { if (node != null) { return(UpdateTreeNode()); } ProjectTreeFlags filteredFlags = FilterFlags(viewModel.Flags); return(isProjectItem ? CreateProjectItemTreeNode() : CreateProjectTreeNode()); IProjectTree CreateProjectTreeNode() { return(_treeServices.CreateTree( caption: viewModel.Caption, filePath: viewModel.FilePath, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree CreateProjectItemTreeNode() { var itemContext = ProjectPropertiesContext.GetContext( _commonServices.Project, file: viewModel.FilePath, itemType: viewModel.SchemaItemType, itemName: viewModel.FilePath); return(_treeServices.CreateTree( caption: viewModel.Caption, itemContext: itemContext, browseObjectProperties: browseObjectProperties, icon: viewModel.Icon.ToProjectSystemType(), expandedIcon: viewModel.ExpandedIcon.ToProjectSystemType(), visible: true, flags: filteredFlags)); } IProjectTree UpdateTreeNode() { var updatedNodeParentContext = new ProjectTreeCustomizablePropertyContext { ExistsOnDisk = false, ParentNodeFlags = node !.Parent?.Flags ?? default }; var updatedValues = new ReferencesProjectTreeCustomizablePropertyValues { Caption = viewModel.Caption, Flags = viewModel.Flags, Icon = viewModel.Icon.ToProjectSystemType(), ExpandedIcon = viewModel.ExpandedIcon.ToProjectSystemType() }; foreach (Lazy <IProjectTreePropertiesProvider, IOrderPrecedenceMetadataView> provider in _projectTreePropertiesProviders) { provider.Value.CalculatePropertyValues(updatedNodeParentContext, updatedValues); } return(node.SetProperties( caption: updatedValues.Caption, browseObjectProperties: browseObjectProperties, icon: updatedValues.Icon, expandedIcon: updatedValues.ExpandedIcon, flags: updatedValues.Flags)); } ProjectTreeFlags FilterFlags(ProjectTreeFlags flags) { if (additionalFlags.HasValue) { flags = flags.Union(additionalFlags.Value); } if (excludedFlags.HasValue) { flags = flags.Except(excludedFlags.Value); } return(flags); } }
/// <summary> /// Gets the properties for a property or item. /// </summary> public IProjectProperties GetProperties(string file, string itemType, string item) { return(new SourceFileProperties(ProjectPropertiesContext.GetContext(_unconfiguredProject, itemType, item), _workspace, _threadingService)); }