Remove excessive shortcut key matching in ToolStrip
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / CompositionContainer.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.Collections.ObjectModel;\r
7 using System.ComponentModel.Composition.Primitives;\r
8 using System.Diagnostics;\r
9 using System.Diagnostics.CodeAnalysis;\r
10 using System.Linq;\r
11 using Microsoft.Internal;\r
12 using Microsoft.Internal.Collections;\r
13 using System.Threading;\r
14 \r
15 namespace System.ComponentModel.Composition.Hosting\r
16 {\r
17     public partial class CompositionContainer : ExportProvider, ICompositionService, IDisposable\r
18     {\r
19         private ImportEngine _importEngine;\r
20         private ComposablePartExportProvider _partExportProvider;\r
21         private AggregateExportProvider _aggregatingExportProvider;\r
22         private ExportProvider _rootProvider;\r
23         private CatalogExportProvider _catalogExportProvider;\r
24         private readonly ReadOnlyCollection<ExportProvider> _providers;\r
25         private volatile int _isDisposed = 0;\r
26 \r
27         /// <summary>\r
28         ///     Initializes a new instance of the <see cref="CompositionContainer"/> class.\r
29         /// </summary>\r
30         public CompositionContainer()\r
31             : this((ComposablePartCatalog)null)\r
32         {\r
33         }\r
34 \r
35         /// <summary>\r
36         ///     Initializes a new instance of the <see cref="CompositionContainer"/> class \r
37         ///     with the specified export providers.\r
38         /// </summary>\r
39         /// <param name="providers">\r
40         ///     A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide \r
41         ///     the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects,\r
42         ///     or <see langword="null"/> to set <see cref="Providers"/> to an empty\r
43         ///     <see cref="ReadOnlyCollection{T}"/>.\r
44         /// </param>\r
45         /// <exception cref="ArgumentException">\r
46         ///     <paramref name="providers"/> contains an element that is <see langword="null"/>.\r
47         /// </exception>\r
48         public CompositionContainer(params ExportProvider[] providers) : \r
49             this((ComposablePartCatalog)null, providers)\r
50         {\r
51         }\r
52 \r
53         /// <summary>\r
54         ///     Initializes a new instance of the <see cref="CompositionContainer"/> class \r
55         ///     with the specified catalog and export providers.\r
56         /// </summary>\r
57         /// <param name="providers">\r
58         ///     A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide \r
59         ///     the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects,\r
60         ///     or <see langword="null"/> to set <see cref="Providers"/> to an empty \r
61         ///     <see cref="ReadOnlyCollection{T}"/>.\r
62         /// </param>\r
63         /// <exception cref="ArgumentException">\r
64         ///     <paramref name="providers"/> contains an element that is <see langword="null"/>.\r
65         /// </exception>\r
66         public CompositionContainer(ComposablePartCatalog catalog, params ExportProvider[] providers): \r
67             this(catalog, false, providers)\r
68         {\r
69         }\r
70 \r
71         public CompositionContainer(ComposablePartCatalog catalog, bool isThreadSafe, params ExportProvider[] providers)\r
72         {\r
73             this._importEngine = new ImportEngine(this, isThreadSafe);\r
74             this._partExportProvider = new ComposablePartExportProvider(isThreadSafe);\r
75             this._partExportProvider.SourceProvider = this;\r
76             this._providers = new ReadOnlyCollection<ExportProvider>(providers != null ? (ExportProvider[])providers.Clone() : new ExportProvider[0]);\r
77 \r
78             List<ExportProvider> providerList = new List<ExportProvider>();\r
79 \r
80             providerList.Add(this._partExportProvider);\r
81 \r
82             if (catalog != null)\r
83             {\r
84                 this._catalogExportProvider = new CatalogExportProvider(catalog, isThreadSafe);\r
85                 this._catalogExportProvider.SourceProvider = this;\r
86 \r
87                 providerList.Add(this._catalogExportProvider);\r
88             }\r
89 \r
90             foreach (var provider in this._providers)\r
91             {\r
92                 if (provider == null)\r
93                 {\r
94                     throw ExceptionBuilder.CreateContainsNullElement("providers");\r
95                 }\r
96                 providerList.Add(provider);\r
97             }\r
98 \r
99             // we only build the aggregating provider if necessary - that is, if we have more than one provider to aggregate\r
100             if (providerList.Count > 1)\r
101             {\r
102                 this._aggregatingExportProvider = new AggregateExportProvider(providerList);\r
103                 this._rootProvider = this._aggregatingExportProvider;\r
104             }\r
105             else\r
106             {\r
107                 Assumes.IsTrue(providerList.Count == 1);\r
108                 this._rootProvider = providerList[0];\r
109             }\r
110 \r
111             this._rootProvider.ExportsChanged += this.OnExportsChangedInternal;\r
112             this._rootProvider.ExportsChanging += this.OnExportsChangingInternal;\r
113         }\r
114 \r
115         /// <summary>\r
116         ///     Gets the catalog which provides the container access to exports produced\r
117         ///     from composable parts.\r
118         /// </summary>\r
119         /// <value>\r
120         ///     The <see cref="ComposablePartCatalog"/> which provides the \r
121         ///     <see cref="CompositionContainer"/> access to exports produced from\r
122         ///     <see cref="ComposablePart"/> objects. The default is <see langword="null"/>.\r
123         /// </value>\r
124         /// <exception cref="ObjectDisposedException">\r
125         ///     The <see cref="CompositionContainer"/> has been disposed of.\r
126         /// </exception>\r
127         public ComposablePartCatalog Catalog\r
128         {\r
129             get \r
130             {\r
131                 ThrowIfDisposed();\r
132 \r
133                 if (_catalogExportProvider != null)\r
134                 {\r
135                     return _catalogExportProvider.Catalog;\r
136                 }\r
137 \r
138                 return null;\r
139             }\r
140         }\r
141 \r
142         /// <summary>\r
143         ///     Gets the export providers which provide the container access to additional exports.\r
144         /// </summary>\r
145         /// <value>\r
146         ///     A <see cref="ReadOnlyCollection{T}"/> of <see cref="ExportProvider"/> objects\r
147         ///     which provide the <see cref="CompositionContainer"/> access to additional\r
148         ///     <see cref="Export"/> objects. The default is an empty \r
149         ///     <see cref="ReadOnlyCollection{T}"/>.\r
150         /// </value>\r
151         /// <exception cref="ObjectDisposedException">\r
152         ///     The <see cref="CompositionContainer"/> has been disposed of.\r
153         /// </exception>\r
154         public ReadOnlyCollection<ExportProvider> Providers\r
155         {\r
156             get\r
157             {\r
158                 this.ThrowIfDisposed();\r
159 \r
160                 return this._providers;\r
161             }\r
162         }\r
163 \r
164         /// <summary>\r
165         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\r
166         /// </summary>\r
167         public void Dispose()\r
168         {\r
169             this.Dispose(true);\r
170             GC.SuppressFinalize(this);\r
171         }\r
172 \r
173         /// <summary>\r
174         /// Releases unmanaged and - optionally - managed resources\r
175         /// </summary>\r
176         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>\r
177         protected virtual void Dispose(bool disposing)\r
178         {\r
179             if (disposing)\r
180             {\r
181                 // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API.\r
182 #pragma warning disable 420\r
183                 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)\r
184 #pragma warning restore 420\r
185                 {\r
186                     this._rootProvider.ExportsChanged -= this.OnExportsChangedInternal;\r
187                     this._rootProvider.ExportsChanging -= this.OnExportsChangingInternal;\r
188                     if (this._aggregatingExportProvider != null)\r
189                     {\r
190                         this._aggregatingExportProvider.Dispose();\r
191                     }\r
192                     this._partExportProvider.Dispose();\r
193                     if (this._catalogExportProvider != null)\r
194                     {\r
195                         this._catalogExportProvider.Dispose();\r
196                     }\r
197                     this._importEngine.Dispose();   \r
198                 }\r
199             }\r
200         }\r
201   \r
202         public void Compose(CompositionBatch batch)\r
203         {\r
204             Requires.NotNull(batch, "batch");\r
205 \r
206             this.ThrowIfDisposed();\r
207             this._partExportProvider.Compose(batch);\r
208         }\r
209 \r
210         /// <summary>\r
211         ///     Releases the <see cref="Export"/> from the <see cref="CompositionContainer"/>. The behavior\r
212         ///     may vary depending on the implementation of the <see cref="ExportProvider"/> that produced \r
213         ///     the <see cref="Export"/> instance. As a general rule non shared exports should be early \r
214         ///     released causing them to be detached from the container.\r
215         ///\r
216         ///     For example the <see cref="CatalogExportProvider"/> will only release \r
217         ///     an <see cref="Export"/> if it comes from a <see cref="ComposablePart"/> that was constructed\r
218         ///     under a <see cref="CreationPolicy.NonShared" /> context. Release in this context means walking\r
219         ///     the dependency chain of the <see cref="Export"/>s, detaching references from the container and \r
220         ///     calling Dispose on the <see cref="ComposablePart"/>s as needed. If the <see cref="Export"/> \r
221         ///     was constructed under a <see cref="CreationPolicy.Shared" /> context the \r
222         ///     <see cref="CatalogExportProvider"/> will do nothing as it may be in use by other requestors. \r
223         ///     Those will only be detached when the container is itself disposed.\r
224         /// </summary>\r
225         /// <param name="export"><see cref="Export"/> that needs to be released.</param>\r
226         /// <exception cref="ArgumentNullException">\r
227         ///     <paramref name="export"/> is <see langword="null"/>.\r
228         /// </exception>\r
229         [SuppressMessage("Microsoft.Performance", "CA1822")]\r
230         public void ReleaseExport(Export export)\r
231         {\r
232             Requires.NotNull(export, "export");\r
233 \r
234             IDisposable dependency = export as IDisposable;\r
235 \r
236             if (dependency != null)\r
237             {\r
238                 dependency.Dispose();\r
239             }\r
240         }\r
241 \r
242         /// <summary>\r
243         ///     Releases the <see cref="Lazy{T}"/> from the <see cref="CompositionContainer"/>. The behavior\r
244         ///     may vary depending on the implementation of the <see cref="ExportProvider"/> that produced \r
245         ///     the <see cref="Export"/> instance. As a general rule non shared exports should be early \r
246         ///     released causing them to be detached from the container.\r
247         ///\r
248         ///     For example the <see cref="CatalogExportProvider"/> will only release \r
249         ///     an <see cref="Lazy{T}"/> if it comes from a <see cref="ComposablePart"/> that was constructed\r
250         ///     under a <see cref="CreationPolicy.NonShared" /> context. Release in this context means walking\r
251         ///     the dependency chain of the <see cref="Export"/>s, detaching references from the container and \r
252         ///     calling Dispose on the <see cref="ComposablePart"/>s as needed. If the <see cref="Export"/> \r
253         ///     was constructed under a <see cref="CreationPolicy.Shared" /> context the \r
254         ///     <see cref="CatalogExportProvider"/> will do nothing as it may be in use by other requestors. \r
255         ///     Those will only be detached when the container is itself disposed.\r
256         /// </summary>\r
257         /// <param name="export"><see cref="Export"/> that needs to be released.</param>\r
258         /// <exception cref="ArgumentNullException">\r
259         ///     <paramref name="export"/> is <see langword="null"/>.\r
260         /// </exception>\r
261         [SuppressMessage("Microsoft.Performance", "CA1822")]\r
262         public void ReleaseExport<T>(Lazy<T> export)\r
263         {\r
264             Requires.NotNull(export, "export");\r
265 \r
266             IDisposable dependency = export as IDisposable;\r
267 \r
268             if (dependency != null)\r
269             {\r
270                 dependency.Dispose();\r
271             }\r
272         }\r
273 \r
274         /// <summary>\r
275         ///     Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. \r
276         ///     See also <see cref="ReleaseExport"/>.\r
277         /// </summary>\r
278         /// <param name="exports"><see cref="Export"/>s that need to be released.</param>\r
279         /// <exception cref="ArgumentNullException">\r
280         ///     <paramref name="exports"/> is <see langword="null"/>.\r
281         /// </exception>\r
282         /// <exception cref="ArgumentException">\r
283         ///     <paramref name="exports"/> contains an element that is <see langword="null"/>.\r
284         /// </exception>\r
285         public void ReleaseExports(IEnumerable<Export> exports)\r
286         {\r
287             Requires.NotNullOrNullElements(exports, "exports");\r
288 \r
289             foreach (Export export in exports)\r
290             {\r
291                 this.ReleaseExport(export);\r
292             }\r
293         }\r
294 \r
295         /// <summary>\r
296         ///     Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. \r
297         ///     See also <see cref="ReleaseExport"/>.\r
298         /// </summary>\r
299         /// <param name="exports"><see cref="Export"/>s that need to be released.</param>\r
300         /// <exception cref="ArgumentNullException">\r
301         ///     <paramref name="exports"/> is <see langword="null"/>.\r
302         /// </exception>\r
303         /// <exception cref="ArgumentException">\r
304         ///     <paramref name="exports"/> contains an element that is <see langword="null"/>.\r
305         /// </exception>\r
306         [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]\r
307         public void ReleaseExports<T>(IEnumerable<Lazy<T>> exports)\r
308         {\r
309             Requires.NotNullOrNullElements(exports, "exports");\r
310 \r
311             foreach (Lazy<T> export in exports)\r
312             {\r
313                 this.ReleaseExport(export);\r
314             }\r
315         }\r
316 \r
317         /// <summary>\r
318         ///     Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. \r
319         ///     See also <see cref="ReleaseExport"/>.\r
320         /// </summary>\r
321         /// <param name="exports"><see cref="Export"/>s that need to be released.</param>\r
322         /// <exception cref="ArgumentNullException">\r
323         ///     <paramref name="exports"/> is <see langword="null"/>.\r
324         /// </exception>\r
325         /// <exception cref="ArgumentException">\r
326         ///     <paramref name="exports"/> contains an element that is <see langword="null"/>.\r
327         /// </exception>\r
328         [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]\r
329         public void ReleaseExports<T, TMetadataView>(IEnumerable<Lazy<T, TMetadataView>> exports)\r
330         {\r
331             Requires.NotNullOrNullElements(exports, "exports");\r
332 \r
333             foreach (Lazy<T, TMetadataView> export in exports)\r
334             {\r
335                 this.ReleaseExport(export);\r
336             }\r
337         }\r
338 \r
339         /// <summary>\r
340         ///     Sets the imports of the specified composable part exactly once and they will not\r
341         ///     ever be recomposed.\r
342         /// </summary>\r
343         /// <param name="part">\r
344         ///     The <see cref="ComposablePart"/> to set the imports.\r
345         /// </param>\r
346         /// <exception cref="ArgumentNullException">\r
347         ///     <paramref name="part"/> is <see langword="null"/>.\r
348         /// </exception>\r
349         /// <exception cref="CompositionException">\r
350         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will\r
351         ///     contain a collection of errors that occurred.\r
352         /// </exception>\r
353         /// <exception cref="ObjectDisposedException">\r
354         ///     The <see cref="ICompositionService"/> has been disposed of.\r
355         /// </exception>\r
356         public void SatisfyImportsOnce(ComposablePart part)\r
357         {\r
358             this.ThrowIfDisposed();\r
359             this._importEngine.SatisfyImportsOnce(part);\r
360         }\r
361 \r
362         internal void OnExportsChangedInternal(object sender, ExportsChangeEventArgs e)\r
363         {\r
364             this.OnExportsChanged(e);\r
365         }\r
366 \r
367         internal void OnExportsChangingInternal(object sender, ExportsChangeEventArgs e)\r
368         {\r
369             this.OnExportsChanging(e);\r
370         }\r
371 \r
372         /// <summary>\r
373         /// Returns all exports that match the conditions of the specified import.\r
374         /// </summary>\r
375         /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the\r
376         /// <see cref="Export"/> to get.</param>\r
377         /// <returns></returns>\r
378         /// <result>\r
379         /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match\r
380         /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an\r
381         /// empty <see cref="IEnumerable{T}"/>.\r
382         /// </result>\r
383         /// <remarks>\r
384         ///     <note type="inheritinfo">\r
385         /// The implementers should not treat the cardinality-related mismatches as errors, and are not\r
386         /// expected to throw exceptions in those cases.\r
387         /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one,\r
388         /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>.\r
389         /// </note>\r
390         /// </remarks>\r
391         protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)\r
392         {\r
393             this.ThrowIfDisposed();\r
394 \r
395             IEnumerable<Export> exports = null;\r
396             this._rootProvider.TryGetExports(definition, atomicComposition, out exports);\r
397 \r
398             return exports;\r
399         }\r
400 \r
401         [DebuggerStepThrough]\r
402         private void ThrowIfDisposed()\r
403         {\r
404             if (this._isDisposed == 1)\r
405             {\r
406                 throw ExceptionBuilder.CreateObjectDisposed(this);\r
407             }\r
408         }\r
409     }\r
410 }\r