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));
        }
示例#2
0
        /// <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);
        }
示例#4
0
        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);
        }
示例#6
0
        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));
 }