ce6960e10dc138465f81d5c737c9723b65a82a48
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / NamespaceListProperty.cs.back
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.Activities.Presentation
6 {
7     using System.Collections;
8     using System.Collections.Generic;
9     using System.Runtime;
10     using System.ComponentModel;
11     using Microsoft.VisualBasic.Activities;
12     using System.Activities.Presentation.View;
13     using System.Activities.Expressions;
14     using System.Reflection;
15     using System.Collections.ObjectModel;    
16
17     class NamespaceListPropertyDescriptor : PropertyDescriptor
18     {
19         public const string ImportCollectionPropertyName = "Imports";
20         public const string AvailableNamespacesPropertyName = "AvailableNamespaces";
21         public const string NamespacePropertyName = "Namespace";        
22         
23         object instance;
24
25         public NamespaceListPropertyDescriptor(object instance)
26             : base(ImportCollectionPropertyName, null)
27         {
28             this.instance = instance;
29         }
30
31         public override Type ComponentType
32         {
33             get { return this.instance.GetType(); }
34         }
35
36         public override bool IsReadOnly
37         {
38             get
39             {
40                 return true;
41             }
42         }
43
44         public override Type PropertyType
45         {
46             get
47             {
48                 return typeof(NamespaceList);
49             }
50         }
51
52         public override bool IsBrowsable
53         {
54             get
55             {
56                 return false;
57             }
58         }
59
60         public override bool CanResetValue(object component)
61         {
62             return false;
63         }
64
65         public override object GetValue(object component)
66         {
67             VisualBasicSettings settings = VisualBasic.GetSettings(component);
68             IList<AssemblyReference> references;
69             IList<string> namespaces = NamespaceHelper.GetTextExpressionNamespaces(component, out references);
70             if ((namespaces != null) && ((namespaces.Count > 0) || ((namespaces.Count == 0) && (settings == null))))
71             {                                
72                 return new TextExpressionNamespaceList(namespaces, references);
73             }
74             else 
75             {
76                 Fx.Assert(settings != null, "Either VB settings or new TextExpression attached properties should be set");
77                 return new VisualBasicNamespaceList(settings.ImportReferences);
78             }            
79         }
80
81         public override void ResetValue(object component)
82         {
83             IList<AssemblyReference> references;
84             IList<string> importedNamespaces = NamespaceHelper.GetTextExpressionNamespaces(component, out references);
85             if (importedNamespaces != null)
86             {
87                 NamespaceHelper.SetTextExpressionNamespaces(component, null, null);
88             }
89             else
90             {
91                 NamespaceHelper.SetVisualBasicSettings(component, null);
92             }
93         }
94
95         public override void SetValue(object component, object value)
96         {
97             NamespaceList namespaceList = value as NamespaceList;
98             if (namespaceList != null)
99             {
100                 if (namespaceList is VisualBasicNamespaceList)
101                 {
102                     VisualBasicNamespaceList visualBasicNamespaces = namespaceList as VisualBasicNamespaceList;
103                     VisualBasicSettings settings = new VisualBasicSettings();
104                     settings.ImportReferences.UnionWith(visualBasicNamespaces.VisualBasicImports);
105                     NamespaceHelper.SetVisualBasicSettings(component, settings);
106                 }
107                 else 
108                 {
109                     Fx.Assert(namespaceList is TextExpressionNamespaceList, "The namespace list must be either of VisualBaiscSettings or TextExpression attached properties.");
110                     TextExpressionNamespaceList textExpressionNamespace = namespaceList as TextExpressionNamespaceList;
111                     NamespaceHelper.SetTextExpressionNamespaces(
112                         component, 
113                         textExpressionNamespace.TextExpressionNamespaces, 
114                         textExpressionNamespace.TextExpressionReferences);
115                 }
116             }
117             else
118             {
119                 this.ResetValue(component);
120             }
121         }
122
123         public override bool ShouldSerializeValue(object component)
124         {
125             throw FxTrace.Exception.AsError(new NotSupportedException());
126         }
127
128         protected override void FillAttributes(IList attributeList)
129         {
130             attributeList.Add(new BrowsableAttribute(false));
131             base.FillAttributes(attributeList);
132         }
133     }
134
135     class NamespaceData
136     {
137         public string Namespace
138         {
139             get;
140             set;
141         }
142
143         //Used by screen reader
144         public override string ToString()
145         {
146             return this.Namespace;
147         }
148     }
149
150     abstract class NamespaceList : IList
151     {
152         //list of uniqueNamespaces, the element is a tuple of the namespace and a arbitary data for consumer to use
153         List<NamespaceData> uniqueNamespaces;
154         Dictionary<string, List<string>> availableNamespaces;
155
156         protected List<NamespaceData> UniqueNamespaces
157         {
158             get
159             {
160                 if (this.uniqueNamespaces == null)
161                 {
162                     this.uniqueNamespaces = new List<NamespaceData>();
163                 }
164                 return this.uniqueNamespaces;
165             }
166         }
167
168         public Dictionary<string, List<string>> AvailableNamespaces
169         {
170             get
171             {
172                 if (availableNamespaces == null)
173                 {
174                     availableNamespaces = new Dictionary<string, List<string>>();
175                 }
176
177                 return availableNamespaces;
178             }
179         }
180
181         internal int Lookup(string ns)
182         {
183             for (int i = 0; i < this.UniqueNamespaces.Count; i++)
184             {
185                 if (this.UniqueNamespaces[i].Namespace == ns)
186                 {
187                     return i;
188                 }
189             }
190
191             return -1;
192         }
193
194         public int Add(object value)
195         {
196             NamespaceData ns = value as NamespaceData;
197
198             if (ns == null)
199             {
200                 throw FxTrace.Exception.AsError(new ArgumentException(SR.NamespaceListArgumentMustBeNamespaceData, "value"));
201             }
202
203             if (Lookup(ns.Namespace) == -1)
204             {
205                 this.AddCore(ns);
206                 return ((IList)this.UniqueNamespaces).Add(ns);
207             }
208             else
209             {
210                 return -1;
211             }
212         }
213
214         public void Clear()
215         {
216             this.ClearCore();
217             this.UniqueNamespaces.Clear();
218         }
219
220         public bool Contains(object value)
221         {
222             return ((IList)this.UniqueNamespaces).Contains(value);
223         }
224
225         public int IndexOf(object value)
226         {
227             return ((IList)this.UniqueNamespaces).IndexOf(value);
228         }
229
230         public void Insert(int index, object value)
231         {
232             NamespaceData ns = value as NamespaceData;
233             if (ns == null)
234             {
235                 throw FxTrace.Exception.AsError(new ArgumentException(SR.NamespaceListArgumentMustBeNamespaceData, "value"));
236             }
237
238             if (Lookup(ns.Namespace) == -1)
239             {
240                 this.UniqueNamespaces.Insert(index, ns);
241                 this.InsertCore(index, ns);                
242             }
243             else
244             {
245                 throw FxTrace.Exception.AsError(new InvalidOperationException());
246             }
247         }
248
249         public bool IsFixedSize
250         {
251             get { return false; }
252         }
253
254         public bool IsReadOnly
255         {
256             get { return false; }
257         }
258
259         public void Remove(object value)
260         {
261             NamespaceData ns = value as NamespaceData;
262             if (ns == null)
263             {
264                 throw FxTrace.Exception.AsError(new ArgumentException(SR.NamespaceListArgumentMustBeNamespaceData, "value"));
265             }
266
267             int index = this.Lookup(ns.Namespace);
268             if (index != -1)
269             {
270                 RemoveAt(index);
271             }
272         }
273
274         public void RemoveAt(int index)
275         {
276             NamespaceData ns = this.UniqueNamespaces[index];
277
278             RemoveNamespaceFromSet(ns.Namespace);
279
280             this.UniqueNamespaces.RemoveAt(index);
281         }
282
283         public object this[int index]
284         {
285             get
286             {
287                 return this.UniqueNamespaces[index];
288             }
289             set
290             {
291                 NamespaceData ns = value as NamespaceData;
292                 if (ns == null)
293                 {
294                     throw FxTrace.Exception.AsError(new ArgumentException(SR.NamespaceListArgumentMustBeNamespaceData, "value"));
295                 }
296
297                 if (Lookup(ns.Namespace) == -1)
298                 {
299                     this.SetValueAt(index, ns);
300                     this.UniqueNamespaces[index] = ns;
301                 }
302                 else
303                 {
304                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.NamespaceListNoDuplicate));
305                 }
306             }
307         }
308
309         public void CopyTo(Array array, int index)
310         {
311             ((IList)this.UniqueNamespaces).CopyTo(array, index);
312         }
313
314         public int Count
315         {
316             get { return this.UniqueNamespaces.Count; }
317         }
318
319         public bool IsSynchronized
320         {
321             get { return false; }
322         }
323
324         public object SyncRoot
325         {
326             get { return null; }
327         }
328
329         public IEnumerator GetEnumerator()
330         {
331             return this.UniqueNamespaces.GetEnumerator();
332         }
333
334         public void UpdateAssemblyInfo(string importedNamespace)
335         {
336             this.UpdateAssemblyInfoCore(importedNamespace);
337         }
338
339         protected abstract void AddCore(NamespaceData ns);
340         protected abstract void ClearCore();
341         protected abstract void InsertCore(int index, NamespaceData ns);
342         protected abstract void RemoveNamespaceFromSet(string ns);
343         protected abstract void SetValueAt(int index, NamespaceData ns);
344         protected abstract void UpdateAssemblyInfoCore(string importedNamespace);
345     }
346
347     class VisualBasicNamespaceList : NamespaceList
348     {
349         //Since XAML generated by designer will almost always have some designer type in it, designer namespaces will appear in XAML.
350         //And because Runtime design could not destinguish namespaces coming from XAML serialization between namespaces added by users,
351         //designer namespaces will show up in import designer. This is bad user experience because most WF project won't reference designer
352         //assembly. We could safely assume that customers won't use designer namespaces and type in their WF expressions, so we simply
353         //---- designer namespaces out of the namespace list
354         static readonly string[] ----edAssemblies = new string[] 
355         {
356             typeof(ViewStateService).Assembly.GetName().FullName,
357             typeof(ViewStateService).Assembly.GetName().Name,
358         };
359
360         static readonly Collection<string> FrameworkAssemblies = new Collection<string>
361         {
362             typeof(Activity).Assembly.GetName().FullName,
363             typeof(Activity).Assembly.GetName().Name,            
364         };
365
366         static readonly Collection<string> ----sedNamespaces = new Collection<string>
367         {
368             "System.Activities.Composition",
369             "System.Activities.Debugger.Symbol"
370         };
371
372         public VisualBasicNamespaceList(ISet<VisualBasicImportReference> importReferences)
373         {
374             this.VisualBasicImports = importReferences;
375
376             foreach (string ----edAssembly in ----edAssemblies)
377             {
378                 RemoveAssemblyFromSet(----edAssembly);
379             }
380             foreach (VisualBasicImportReference import in importReferences)
381             {
382                 if (!(----sedNamespaces.Contains(import.Import) && FrameworkAssemblies.Contains(import.Assembly)))
383                 {
384                     if (Lookup(import.Import) == -1)
385                     {
386                         this.UniqueNamespaces.Add(new NamespaceData { Namespace = import.Import });
387                     }
388                 }
389             }
390         }
391
392         internal ISet<VisualBasicImportReference> VisualBasicImports
393         {
394             get;
395             private set;
396         }
397
398         IEnumerable<VisualBasicImportReference> GetVisualBasicImportReferences(string importNamespace)
399         {
400             List<VisualBasicImportReference> imports = new List<VisualBasicImportReference>();
401             List<string> assemblies;
402             //in rehost cases or when some assembiles are not referenced, we may not find that namespace
403             if (!this.AvailableNamespaces.TryGetValue(importNamespace, out assemblies))
404             {
405                 return imports;
406             }
407
408             foreach (string assembly in assemblies)
409             {
410                 imports.Add(new VisualBasicImportReference
411                 {
412                     Import = importNamespace,
413                     Assembly = assembly
414                 });
415             }
416             return imports;
417         }
418
419         protected override void UpdateAssemblyInfoCore(string importedNamespace)
420         {
421             if (this.VisualBasicImports != null)
422             {
423                 if (this.Lookup(importedNamespace) != -1)
424                 {
425                     this.VisualBasicImports.UnionWith(GetVisualBasicImportReferences(importedNamespace));
426                 }
427                 else
428                 {
429                     Fx.Assert("UpdateAssemblyInfor should only be called for existed namespace");
430                 }
431             }
432         }
433
434         protected override void RemoveNamespaceFromSet(string ns)
435         {
436             List<VisualBasicImportReference> toRemoves = new List<VisualBasicImportReference>();
437             foreach (VisualBasicImportReference import in this.VisualBasicImports)
438             {
439                 if (import.Import == ns)
440                 {
441                     toRemoves.Add(import);
442                 }
443             }
444
445             foreach (VisualBasicImportReference toRemove in toRemoves)
446             {
447                 this.VisualBasicImports.Remove(toRemove);
448             }
449         }
450
451         private void RemoveAssemblyFromSet(string assembly)
452         {
453             List<VisualBasicImportReference> toRemoves = new List<VisualBasicImportReference>();
454             foreach (VisualBasicImportReference import in this.VisualBasicImports)
455             {
456                 if (import.Assembly == assembly)
457                 {
458                     toRemoves.Add(import);
459                 }
460             }
461
462             foreach (VisualBasicImportReference toRemove in toRemoves)
463             {
464                 this.VisualBasicImports.Remove(toRemove);
465             }
466         }
467
468         protected override void AddCore(NamespaceData ns)
469         {
470             this.VisualBasicImports.UnionWith(GetVisualBasicImportReferences(ns.Namespace));
471         }
472
473         protected override void ClearCore()
474         {
475             this.VisualBasicImports.Clear();
476         }
477
478         protected override void InsertCore(int index, NamespaceData ns)
479         {
480             this.VisualBasicImports.UnionWith(GetVisualBasicImportReferences(ns.Namespace));
481         }
482
483         protected override void SetValueAt(int index, NamespaceData ns)
484         {
485             RemoveNamespaceFromSet(this.UniqueNamespaces[index].Namespace);
486             this.VisualBasicImports.UnionWith(GetVisualBasicImportReferences(ns.Namespace));
487         }
488     }
489
490     class TextExpressionNamespaceList : NamespaceList
491     {
492         public TextExpressionNamespaceList(IList<string> importedNamespaces, IList<AssemblyReference> references)
493         {
494             this.TextExpressionNamespaces = importedNamespaces;
495             this.TextExpressionReferences = references;
496             foreach (string importedNamespace in importedNamespaces)
497             {
498                 if (Lookup(importedNamespace) == -1)
499                 {
500                     this.UniqueNamespaces.Add(new NamespaceData { Namespace = importedNamespace });
501                 }
502             }
503         }
504
505         internal IList<string> TextExpressionNamespaces
506         {
507             get;
508             private set;
509         }
510
511         internal IList<AssemblyReference> TextExpressionReferences
512         {
513             get;
514             private set;
515         }
516
517
518         protected override void RemoveNamespaceFromSet(string ns)
519         {
520             this.TextExpressionNamespaces.Remove(ns);
521         }
522
523         internal void RemoveAssemblyFromSet(string assembly)
524         {
525             AssemblyReference toRemove = null;
526             foreach (AssemblyReference reference in this.TextExpressionReferences)
527             {
528                 if (reference.AssemblyName.Name == assembly)
529                 {
530                     toRemove = reference;
531                     break;
532                 }
533             }
534             if (toRemove != null)
535             {
536                 this.TextExpressionReferences.Remove(toRemove);
537             }
538         }
539
540         private void AddAssemblyToSet(string assembly)
541         {
542             bool isExisted = false;
543             foreach (AssemblyReference reference in this.TextExpressionReferences)
544             {
545                 if (reference.AssemblyName.Name == assembly)
546                 {
547                     isExisted = true;
548                 }
549             }
550
551             if (!isExisted)
552             {
553                 this.TextExpressionReferences.Add(new AssemblyReference { AssemblyName = new AssemblyName(assembly) });
554             }
555         }
556
557         protected override void AddCore(NamespaceData ns)
558         {
559             this.InsertCore(this.TextExpressionNamespaces.Count, ns);
560         }
561
562         protected override void ClearCore()
563         {
564             this.TextExpressionNamespaces.Clear();
565         }
566
567         protected override void InsertCore(int index, NamespaceData ns)
568         {
569             this.TextExpressionNamespaces.Insert(index, ns.Namespace);
570
571             if (this.AvailableNamespaces.ContainsKey(ns.Namespace))
572             {                
573                 foreach (string assembly in this.AvailableNamespaces[ns.Namespace])
574                 {
575                     this.AddAssemblyToSet(assembly);
576                 }
577             }
578         }
579
580         protected override void SetValueAt(int index, NamespaceData ns)
581         {
582             this.TextExpressionNamespaces[index] = ns.Namespace;
583         }
584
585         protected override void UpdateAssemblyInfoCore(string importedNamespace)
586         {            
587             foreach (string assembly in this.AvailableNamespaces[importedNamespace])
588             {
589                 this.AddAssemblyToSet(assembly);
590             }
591         }
592
593     }
594 }