[corlib] Update ValueTuple implementation
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / Microsoft.Tools.Common / Microsoft / Activities / Presentation / Xaml / WorkflowDesignerXamlSchemaContext.cs
1 // <copyright>
2 //   Copyright (c) Microsoft Corporation.  All rights reserved.
3 // </copyright>
4
5 namespace Microsoft.Activities.Presentation.Xaml
6 {
7     using System;
8     using System.Activities.Presentation;
9     using System.Activities.Presentation.Hosting;
10     using System.Activities.Presentation.Xaml;
11     using System.Collections.Generic;
12     using System.ComponentModel;
13     using System.ComponentModel.Composition;
14     using System.Diagnostics.CodeAnalysis;
15     using System.Linq;
16     using System.Reflection;
17     using System.Runtime.CompilerServices;
18     using System.Runtime.Versioning;
19     using System.Xaml;
20     using Microsoft.Activities.Presentation;
21
22     class WorkflowDesignerXamlSchemaContext : XamlSchemaContext
23     {
24         //post fix for xml namespace defined by CLR namespace in local assembly            
25         readonly string localAssemblyNsPostfix;
26         readonly string localAssemblyNsPostfixNoLeadingSemicolon;
27         // Cache of custom XamlTypes
28         Dictionary<Type, XamlType> customXamlTypes;
29         EditingContext editingContext;
30         bool environmentAssembliesLoaded;
31         private readonly static FrameworkName CurrentFramework = FrameworkNameConstants.NetFramework45;
32         private ResolverCache resolverCache;
33
34         private static List<Type> supportedTypes;
35         private static List<Type> conversionRequiredTypes;
36
37         [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
38         static WorkflowDesignerXamlSchemaContext()
39         {
40             supportedTypes = new List<Type>();
41             supportedTypes.Add(typeof(System.Activities.Presentation.Expressions.ExpressionActivityEditor));
42             supportedTypes.Add(typeof(System.Activities.Presentation.Annotations.Annotation));
43
44             conversionRequiredTypes = new List<Type>();
45             conversionRequiredTypes.Add(typeof(System.Activities.Expressions.TextExpression));
46             conversionRequiredTypes.Add(typeof(System.Activities.Expressions.AssemblyReference));
47             conversionRequiredTypes.Add(typeof(System.Collections.ObjectModel.Collection<System.Activities.Expressions.AssemblyReference>));
48             conversionRequiredTypes.Add(typeof(System.Activities.Debugger.Symbol.DebugSymbol));
49             conversionRequiredTypes.Add(typeof(System.Activities.Presentation.ViewState.WorkflowViewState));
50             conversionRequiredTypes.Add(typeof(System.Activities.Presentation.ViewState.ViewStateManager));
51             conversionRequiredTypes.Add(typeof(System.Activities.Presentation.ViewState.ViewStateData));
52         }
53
54         public WorkflowDesignerXamlSchemaContext(string localAssembly) : this(localAssembly, null)
55         {
56         }
57
58         public WorkflowDesignerXamlSchemaContext(string localAssembly, EditingContext editingContext)
59         {
60             if (!string.IsNullOrEmpty(localAssembly))
61             {
62                 this.localAssemblyNsPostfix = XamlNamespaceHelper.ClrNamespaceAssemblyField + localAssembly;
63                 this.localAssemblyNsPostfixNoLeadingSemicolon = localAssemblyNsPostfix.Substring(1);
64             }
65             this.editingContext = editingContext;
66         }
67
68         internal bool ContainsConversionRequiredType { get; set; }
69
70         protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments)
71         {
72             if (!string.IsNullOrEmpty(this.localAssemblyNsPostfix)
73                 && IsClrNamespaceWithNoAssembly(xamlNamespace))
74             {
75                 xamlNamespace = AddLocalAssembly(xamlNamespace);
76             }
77
78             var xamlType = base.GetXamlType(xamlNamespace, name, typeArguments);
79
80             if (xamlType == null && environmentAssembliesLoaded == false && editingContext != null)
81             {
82                 // Failed to find the type, this might because the namespace is a custom namespace
83                 //  and the dependent assembly hasn't been loaded yet. Load all dependent assemblies
84                 //  and try to load the same xaml type again.
85                 AssemblyContextControlItem assemblyItem = this.editingContext.Items.GetValue<AssemblyContextControlItem>();
86                 var environmentAssemblies = assemblyItem.GetEnvironmentAssemblies(null);
87                 if (assemblyItem.LocalAssemblyName != null)
88                 {
89                     AssemblyContextControlItem.GetAssembly(assemblyItem.LocalAssemblyName, null);
90                 }
91
92                 environmentAssembliesLoaded = true;
93                 xamlType = base.GetXamlType(xamlNamespace, name, typeArguments);
94             }
95
96             if (xamlType == null || xamlType.UnderlyingType == null || this.editingContext == null)
97             {
98                 return xamlType;
99             }
100
101             MultiTargetingSupportService multiTargetingService = editingContext.Services.GetService<IMultiTargetingSupportService>() as MultiTargetingSupportService;
102             DesignerConfigurationService config = editingContext.Services.GetService<DesignerConfigurationService>();
103             if (multiTargetingService == null || config == null)
104             {
105                 return xamlType;
106             }
107
108             // do not filter out new types and new properties if targeting to current framework and it's a full SKU
109             if (config.TargetFrameworkName.Version == CurrentFramework.Version && config.TargetFrameworkName.IsFullProfile())
110             {
111                 return xamlType;
112             }
113
114             // Filter out new types and new properties
115             if (this.resolverCache == null)
116             {
117                 this.resolverCache = new ResolverCache();
118             }
119
120             if (supportedTypes.Contains(xamlType.UnderlyingType))
121             {
122                 return xamlType;
123             }
124
125             // only check if conversion is needed when target framework is less than 4.5
126             if (config.TargetFrameworkName.Version < CurrentFramework.Version)
127             {
128                 if (conversionRequiredTypes.Contains(xamlType.UnderlyingType))
129                 {
130                     this.ContainsConversionRequiredType = true;
131                     return xamlType;
132                 }
133             }
134
135             ResolverResult resolverResult = this.resolverCache.Lookup(xamlType.UnderlyingType);
136             if (resolverResult == null)
137             {
138                 resolverResult = MultiTargetingTypeResolver.Resolve(multiTargetingService, xamlType.UnderlyingType);
139                 this.resolverCache.Update(xamlType.UnderlyingType, resolverResult);
140             }
141
142             return MultiTargetingTypeResolver.GetXamlType(resolverResult, xamlType);
143         }
144
145         public override XamlType GetXamlType(Type type)
146         {            
147             XamlType xamlType = null;
148             if (this.customXamlTypes != null && this.customXamlTypes.TryGetValue(type, out xamlType))
149             {
150                 return xamlType;
151             }
152             bool isCustom = false;
153             xamlType = GetCustomType(type);
154             if (xamlType != null)
155             {
156                 isCustom = true;
157             }
158             else
159             {
160                 xamlType = base.GetXamlType(type);
161                 if (xamlType.GetXamlNamespaces().Any(ns => IsClrNamespaceInLocalAssembly(ns)))
162                 {
163                     isCustom = true;
164                     xamlType = new XamlTypeWithExplicitNamespace(xamlType, xamlType.GetXamlNamespaces().Select(ns => IsClrNamespaceInLocalAssembly(ns) ? TrimLocalAssembly(ns) : ns));
165                 }
166             }
167             if (isCustom)
168             {
169                 if (this.customXamlTypes == null)
170                 {
171                     this.customXamlTypes = new Dictionary<Type, XamlType>();
172                 }
173                 this.customXamlTypes[type] = xamlType;
174             }
175             return xamlType;
176         }
177
178         public override IEnumerable<string> GetAllXamlNamespaces()
179         {
180             foreach (string ns in base.GetAllXamlNamespaces())
181             {
182                 if (IsClrNamespaceInLocalAssembly(ns))
183                 {
184                     yield return TrimLocalAssembly(ns);
185                 }
186                 else
187                 {
188                     yield return ns;
189                 }
190             }
191         }
192
193         internal bool HasLocalAssembly
194         {
195             get { return !string.IsNullOrEmpty(this.localAssemblyNsPostfix); }
196         }
197
198         internal string AddLocalAssembly(string ns)
199         {
200             string result = ns;
201             // clr-namespace:X.Y.Z ==> clr-namespace:X.Y.Z;assembly=MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
202             if (result[result.Length - 1] != ';')
203             {
204                 result += this.localAssemblyNsPostfix;
205             }
206             else
207             {
208                 result += this.localAssemblyNsPostfixNoLeadingSemicolon;
209             }
210             return result;
211         }
212
213         internal bool IsClrNamespaceWithNoAssembly(string ns)
214         {
215             //could be more sophisticated with a RegEx, but let's keep it simple for now
216             return ns.StartsWith(XamlNamespaceHelper.ClrNamespacePrefix, StringComparison.OrdinalIgnoreCase) &&
217                 ns.IndexOf(XamlNamespaceHelper.ClrNamespaceAssemblyField, StringComparison.OrdinalIgnoreCase) == -1;
218         }
219
220         internal bool IsClrNamespaceInLocalAssembly(string ns)
221         {
222             //could be more sophisticated with a RegEx, but let's keep it simple for now
223
224             return !string.IsNullOrEmpty(this.localAssemblyNsPostfix) && ns.EndsWith(this.localAssemblyNsPostfix, StringComparison.OrdinalIgnoreCase);
225         }
226
227         internal string TrimLocalAssembly(string ns)
228         {
229             return string.IsNullOrEmpty(this.localAssemblyNsPostfix) ? ns : ns.Substring(0, ns.Length - this.localAssemblyNsPostfix.Length);
230         }
231
232         XamlType GetCustomType(Type type)
233         {
234             if (type == typeof(DesignerAttribute))
235             {
236                 return new AttributeXamlType<DesignerAttribute, DesignerAttributeInfo>(this);
237             }
238             if (type == typeof(EditorAttribute))
239             {
240                 return new AttributeXamlType<EditorAttribute, EditorAttributeInfo>(this);
241             }
242             if (type == typeof(DefaultValueAttribute))
243             {
244                 return new AttributeXamlType<DefaultValueAttribute, DefaultValueAttributeInfo>(this);
245             }
246             if (type.Namespace == "System.ComponentModel.Composition")
247             {
248                 return GetCustomMefType(type);
249             }
250 #if ERROR_TOLERANT_SUPPORT
251             if (ErrorTolerantObjectWriter.IsErrorActivity(type))
252             {
253                 return new ShimAsPublicXamlType(type, this);
254             }
255 #endif
256             return null;
257         }
258
259         // Avoid loading System.ComponentModel.Composition unless we need it
260         [MethodImpl(MethodImplOptions.NoInlining)]
261         XamlType GetCustomMefType(Type type)
262         {
263             if (type == typeof(ImportAttribute))
264             {
265                 return new AttributeXamlType<ImportAttribute, ImportAttributeInfo>(this);
266             }
267             if (type == typeof(ImportManyAttribute))
268             {
269                 return new AttributeXamlType<ImportAttribute, ImportAttributeInfo>(this);
270             }
271             return null;
272         }
273     }
274 }