~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/mono-addins/Mono.Addins/Mono.Addins/ExtensionContext.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// ExtensionContext.cs
 
3
//
 
4
// Author:
 
5
//   Lluis Sanchez Gual
 
6
//
 
7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
// 
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
// 
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
 
 
30
using System;
 
31
using System.Collections;
 
32
using System.Collections.Generic;
 
33
using System.Collections.Specialized;
 
34
using Mono.Addins.Description;
 
35
 
 
36
namespace Mono.Addins
 
37
{
 
38
        /// <summary>
 
39
        /// An extension context.
 
40
        /// </summary>
 
41
        /// <remarks>
 
42
        /// Extension contexts can be used to query the extension tree
 
43
        /// using particular condition values. Extension points which
 
44
        /// declare the availability of a condition type can only be
 
45
        /// queryed using an extension context which provides an
 
46
        /// evaluator for that condition.
 
47
        /// </remarks>
 
48
        public class ExtensionContext
 
49
        {
 
50
                Hashtable conditionTypes = new Hashtable ();
 
51
                Hashtable conditionsToNodes = new Hashtable ();
 
52
                List<WeakReference> childContexts;
 
53
                ExtensionContext parentContext;
 
54
                ExtensionTree tree;
 
55
                bool fireEvents = false;
 
56
                
 
57
                ArrayList runTimeEnabledAddins;
 
58
                ArrayList runTimeDisabledAddins;
 
59
                
 
60
                /// <summary>
 
61
                /// Extension change event.
 
62
                /// </summary>
 
63
                /// <remarks>
 
64
                /// This event is fired when any extension point in the add-in system changes.
 
65
                /// The event args object provides the path of the changed extension, although
 
66
                /// it does not provide information about what changed. Hosts subscribing to
 
67
                /// this event should get the new list of nodes using a query method such as
 
68
                /// AddinManager.GetExtensionNodes() and then update whatever needs to be updated.
 
69
                /// </remarks>
 
70
                public event ExtensionEventHandler ExtensionChanged;
 
71
                
 
72
                internal void Initialize (AddinEngine addinEngine)
 
73
                {
 
74
                        fireEvents = false;
 
75
                        tree = new ExtensionTree (addinEngine, this);
 
76
                }
 
77
 
 
78
#pragma warning disable 1591
 
79
                [ObsoleteAttribute]
 
80
                protected void Clear ()
 
81
                {
 
82
                }
 
83
#pragma warning restore 1591
 
84
 
 
85
                
 
86
                internal void ClearContext ()
 
87
                {
 
88
                        conditionTypes.Clear ();
 
89
                        conditionsToNodes.Clear ();
 
90
                        childContexts = null;
 
91
                        parentContext = null;
 
92
                        tree = null;
 
93
                        runTimeEnabledAddins = null;
 
94
                        runTimeDisabledAddins = null;
 
95
                }
 
96
                
 
97
                internal AddinEngine AddinEngine {
 
98
                        get { return tree.AddinEngine; }
 
99
                }
 
100
 
 
101
                void CleanDisposedChildContexts ()
 
102
                {
 
103
                        if (childContexts != null)
 
104
                                childContexts.RemoveAll (w => w.Target == null);
 
105
                }
 
106
                
 
107
                internal virtual void ResetCachedData ()
 
108
                {
 
109
                        tree.ResetCachedData ();
 
110
                        if (childContexts != null) {
 
111
                                foreach (WeakReference wref in childContexts) {
 
112
                                        ExtensionContext ctx = wref.Target as ExtensionContext;
 
113
                                        if (ctx != null)
 
114
                                                ctx.ResetCachedData ();
 
115
                                }
 
116
                        }
 
117
                }
 
118
                
 
119
                internal ExtensionContext CreateChildContext ()
 
120
                {
 
121
                        lock (conditionTypes) {
 
122
                                if (childContexts == null)
 
123
                                        childContexts = new List<WeakReference> ();
 
124
                                else
 
125
                                        CleanDisposedChildContexts ();
 
126
                                ExtensionContext ctx = new ExtensionContext ();
 
127
                                ctx.Initialize (AddinEngine);
 
128
                                ctx.parentContext = this;
 
129
                                WeakReference wref = new WeakReference (ctx);
 
130
                                childContexts.Add (wref);
 
131
                                return ctx;
 
132
                        }
 
133
                }
 
134
 
 
135
                /// <summary>
 
136
                /// Registers a new condition in the extension context.
 
137
                /// </summary>
 
138
                /// <param name="id">
 
139
                /// Identifier of the condition.
 
140
                /// </param>
 
141
                /// <param name="type">
 
142
                /// Condition evaluator.
 
143
                /// </param>
 
144
                /// <remarks>
 
145
                /// The registered condition will be particular to this extension context.
 
146
                /// Any event that might be fired as a result of changes in the condition will
 
147
                /// only be fired in this context.
 
148
                /// </remarks>
 
149
                public void RegisterCondition (string id, ConditionType type)
 
150
                {
 
151
                        type.Id = id;
 
152
                        ConditionInfo info = CreateConditionInfo (id);
 
153
                        ConditionType ot = info.CondType as ConditionType;
 
154
                        if (ot != null)
 
155
                                ot.Changed -= new EventHandler (OnConditionChanged);
 
156
                        info.CondType = type;
 
157
                        type.Changed += new EventHandler (OnConditionChanged);
 
158
                }
 
159
                
 
160
                /// <summary>
 
161
                /// Registers a new condition in the extension context.
 
162
                /// </summary>
 
163
                /// <param name="id">
 
164
                /// Identifier of the condition.
 
165
                /// </param>
 
166
                /// <param name="type">
 
167
                /// Type of the condition evaluator. Must be a subclass of Mono.Addins.ConditionType.
 
168
                /// </param>
 
169
                /// <remarks>
 
170
                /// The registered condition will be particular to this extension context. Any event
 
171
                /// that might be fired as a result of changes in the condition will only be fired in this context.
 
172
                /// </remarks>
 
173
                public void RegisterCondition (string id, Type type)
 
174
                {
 
175
                        // Allows delayed creation of condition types
 
176
                        ConditionInfo info = CreateConditionInfo (id);
 
177
                        ConditionType ot = info.CondType as ConditionType;
 
178
                        if (ot != null)
 
179
                                ot.Changed -= new EventHandler (OnConditionChanged);
 
180
                        info.CondType = type;
 
181
                }
 
182
                
 
183
                ConditionInfo CreateConditionInfo (string id)
 
184
                {
 
185
                        ConditionInfo info = conditionTypes [id] as ConditionInfo;
 
186
                        if (info == null) {
 
187
                                info = new ConditionInfo ();
 
188
                                conditionTypes [id] = info;
 
189
                        }
 
190
                        return info;
 
191
                }
 
192
                
 
193
                internal bool FireEvents {
 
194
                        get { return fireEvents; }
 
195
                }
 
196
                
 
197
                internal ConditionType GetCondition (string id)
 
198
                {
 
199
                        ConditionType ct;
 
200
                        ConditionInfo info = (ConditionInfo) conditionTypes [id];
 
201
                        
 
202
                        if (info != null) {
 
203
                                if (info.CondType is Type) {
 
204
                                        // The condition was registered as a type, create an instance now
 
205
                                        ct = (ConditionType) Activator.CreateInstance ((Type)info.CondType);
 
206
                                        ct.Id = id;
 
207
                                        ct.Changed += new EventHandler (OnConditionChanged);
 
208
                                        info.CondType = ct;
 
209
                                }
 
210
                                else
 
211
                                        ct = info.CondType as ConditionType;
 
212
 
 
213
                                if (ct != null)
 
214
                                        return ct;
 
215
                        }
 
216
                        
 
217
                        if (parentContext != null)
 
218
                                return parentContext.GetCondition (id);
 
219
                        else
 
220
                                return null;
 
221
                }
 
222
                
 
223
                internal void RegisterNodeCondition (TreeNode node, BaseCondition cond)
 
224
                {
 
225
                        ArrayList list = (ArrayList) conditionsToNodes [cond];
 
226
                        if (list == null) {
 
227
                                list = new ArrayList ();
 
228
                                conditionsToNodes [cond] = list;
 
229
                                ArrayList conditionTypeIds = new ArrayList ();
 
230
                                cond.GetConditionTypes (conditionTypeIds);
 
231
                                
 
232
                                foreach (string cid in conditionTypeIds) {
 
233
                                
 
234
                                        // Make sure the condition is properly created
 
235
                                        GetCondition (cid);
 
236
                                        
 
237
                                        ConditionInfo info = CreateConditionInfo (cid);
 
238
                                        if (info.BoundConditions == null)
 
239
                                                info.BoundConditions = new ArrayList ();
 
240
                                                
 
241
                                        info.BoundConditions.Add (cond);
 
242
                                }
 
243
                        }
 
244
                        list.Add (node);
 
245
                }
 
246
                
 
247
                internal void UnregisterNodeCondition (TreeNode node, BaseCondition cond)
 
248
                {
 
249
                        ArrayList list = (ArrayList) conditionsToNodes [cond];
 
250
                        if (list == null)
 
251
                                return;
 
252
                        
 
253
                        list.Remove (node);
 
254
                        if (list.Count == 0) {
 
255
                                conditionsToNodes.Remove (cond);
 
256
                                ArrayList conditionTypeIds = new ArrayList ();
 
257
                                cond.GetConditionTypes (conditionTypeIds);
 
258
                                foreach (string cid in conditionTypes.Keys) {
 
259
                                        ConditionInfo info = conditionTypes [cid] as ConditionInfo;
 
260
                                        if (info != null && info.BoundConditions != null)
 
261
                                                info.BoundConditions.Remove (cond);
 
262
                                }
 
263
                        }
 
264
                }
 
265
                
 
266
                /// <summary>
 
267
                /// Returns the extension node in a path
 
268
                /// </summary>
 
269
                /// <param name="path">
 
270
                /// Location of the node.
 
271
                /// </param>
 
272
                /// <returns>
 
273
                /// The node, or null if not found.
 
274
                /// </returns>
 
275
                public ExtensionNode GetExtensionNode (string path)
 
276
                {
 
277
                        TreeNode node = GetNode (path);
 
278
                        if (node == null)
 
279
                                return null;
 
280
                        
 
281
                        if (node.Condition == null || node.Condition.Evaluate (this))
 
282
                                return node.ExtensionNode;
 
283
                        else
 
284
                                return null;
 
285
                }
 
286
                
 
287
                /// <summary>
 
288
                /// Returns the extension node in a path
 
289
                /// </summary>
 
290
                /// <param name="path">
 
291
                /// Location of the node.
 
292
                /// </param>
 
293
                /// <returns>
 
294
                /// The node, or null if not found.
 
295
                /// </returns>
 
296
                public T GetExtensionNode<T> (string path) where T: ExtensionNode
 
297
                {
 
298
                        return (T) GetExtensionNode (path);
 
299
                }
 
300
                
 
301
                /// <summary>
 
302
                /// Gets extension nodes registered in a path.
 
303
                /// </summary>
 
304
                /// <param name="path">
 
305
                /// An extension path.>
 
306
                /// </param>
 
307
                /// <returns>
 
308
                /// All nodes registered in the provided path.
 
309
                /// </returns>
 
310
                public ExtensionNodeList GetExtensionNodes (string path)
 
311
                {
 
312
                        return GetExtensionNodes (path, null);
 
313
                }
 
314
                
 
315
                /// <summary>
 
316
                /// Gets extension nodes registered in a path.
 
317
                /// </summary>
 
318
                /// <param name="path">
 
319
                /// An extension path.
 
320
                /// </param>
 
321
                /// <returns>
 
322
                /// A list of nodes
 
323
                /// </returns>
 
324
                /// <remarks>
 
325
                /// This method returns all nodes registered under the provided path.
 
326
                /// It will throw a InvalidOperationException if the type of one of
 
327
                /// the registered nodes is not assignable to the provided type.
 
328
                /// </remarks>
 
329
                public ExtensionNodeList<T> GetExtensionNodes<T> (string path) where T: ExtensionNode
 
330
                {
 
331
                        ExtensionNodeList nodes = GetExtensionNodes (path, typeof(T));
 
332
                        return new ExtensionNodeList<T> (nodes.list);
 
333
                }
 
334
                
 
335
                /// <summary>
 
336
                /// Gets extension nodes for a type extension point
 
337
                /// </summary>
 
338
                /// <param name="instanceType">
 
339
                /// Type defining the extension point
 
340
                /// </param>
 
341
                /// <returns>
 
342
                /// A list of nodes
 
343
                /// </returns>
 
344
                /// <remarks>
 
345
                /// This method returns all extension nodes bound to the provided type.
 
346
                /// </remarks>
 
347
                public ExtensionNodeList GetExtensionNodes (Type instanceType)
 
348
                {
 
349
                        return GetExtensionNodes (instanceType, typeof(ExtensionNode));
 
350
                }
 
351
                
 
352
                /// <summary>
 
353
                /// Gets extension nodes for a type extension point
 
354
                /// </summary>
 
355
                /// <param name="instanceType">
 
356
                /// Type defining the extension point
 
357
                /// </param>
 
358
                /// <param name="expectedNodeType">
 
359
                /// Expected extension node type
 
360
                /// </param>
 
361
                /// <returns>
 
362
                /// A list of nodes
 
363
                /// </returns>
 
364
                /// <remarks>
 
365
                /// This method returns all nodes registered for the provided type.
 
366
                /// It will throw a InvalidOperationException if the type of one of
 
367
                /// the registered nodes is not assignable to the provided node type.
 
368
                /// </remarks>
 
369
                public ExtensionNodeList GetExtensionNodes (Type instanceType, Type expectedNodeType)
 
370
                {
 
371
                        string path = AddinEngine.GetAutoTypeExtensionPoint (instanceType);
 
372
                        if (path == null)
 
373
                                return new ExtensionNodeList (null);
 
374
                        return GetExtensionNodes (path, expectedNodeType);
 
375
                }
 
376
                
 
377
                /// <summary>
 
378
                /// Gets extension nodes for a type extension point
 
379
                /// </summary>
 
380
                /// <param name="instanceType">
 
381
                /// Type defining the extension point
 
382
                /// </param>
 
383
                /// <returns>
 
384
                /// A list of nodes
 
385
                /// </returns>
 
386
                /// <remarks>
 
387
                /// This method returns all nodes registered for the provided type.
 
388
                /// It will throw a InvalidOperationException if the type of one of
 
389
                /// the registered nodes is not assignable to the specified node type argument.
 
390
                /// </remarks>
 
391
                public ExtensionNodeList<T> GetExtensionNodes<T> (Type instanceType) where T: ExtensionNode
 
392
                {
 
393
                        string path = AddinEngine.GetAutoTypeExtensionPoint (instanceType);
 
394
                        if (path == null)
 
395
                                return new ExtensionNodeList<T> (null);
 
396
                        return new ExtensionNodeList<T> (GetExtensionNodes (path, typeof (T)).list);
 
397
                }
 
398
                
 
399
                /// <summary>
 
400
                /// Gets extension nodes registered in a path.
 
401
                /// </summary>
 
402
                /// <param name="path">
 
403
                /// An extension path.
 
404
                /// </param>
 
405
                /// <param name="expectedNodeType">
 
406
                /// Expected node type.
 
407
                /// </param>
 
408
                /// <returns>
 
409
                /// A list of nodes
 
410
                /// </returns>
 
411
                /// <remarks>
 
412
                /// This method returns all nodes registered under the provided path.
 
413
                /// It will throw a InvalidOperationException if the type of one of
 
414
                /// the registered nodes is not assignable to the provided type.
 
415
                /// </remarks>
 
416
                public ExtensionNodeList GetExtensionNodes (string path, Type expectedNodeType)
 
417
                {
 
418
                        TreeNode node = GetNode (path);
 
419
                        if (node == null || node.ExtensionNode == null)
 
420
                                return ExtensionNodeList.Empty;
 
421
                        
 
422
                        ExtensionNodeList list = node.ExtensionNode.ChildNodes;
 
423
                        
 
424
                        if (expectedNodeType != null) {
 
425
                                bool foundError = false;
 
426
                                foreach (ExtensionNode cnode in list) {
 
427
                                        if (!expectedNodeType.IsInstanceOfType (cnode)) {
 
428
                                                foundError = true;
 
429
                                                AddinEngine.ReportError ("Error while getting nodes for path '" + path + "'. Expected subclass of node type '" + expectedNodeType + "'. Found '" + cnode.GetType (), null, null, false);
 
430
                                        }
 
431
                                }
 
432
                                if (foundError) {
 
433
                                        // Create a new list excluding the elements that failed the test
 
434
                                        List<ExtensionNode> newList = new List<ExtensionNode> ();
 
435
                                        foreach (ExtensionNode cnode in list) {
 
436
                                                if (expectedNodeType.IsInstanceOfType (cnode))
 
437
                                                        newList.Add (cnode);
 
438
                                        }
 
439
                                        return new ExtensionNodeList (newList);
 
440
                                }
 
441
                        }
 
442
                        return list;
 
443
                }
 
444
                
 
445
                /// <summary>
 
446
                /// Gets extension objects registered for a type extension point.
 
447
                /// </summary>
 
448
                /// <param name="instanceType">
 
449
                /// Type defining the extension point
 
450
                /// </param>
 
451
                /// <returns>
 
452
                /// A list of objects
 
453
                /// </returns>
 
454
                public object[] GetExtensionObjects (Type instanceType)
 
455
                {
 
456
                        return GetExtensionObjects (instanceType, true);
 
457
                }
 
458
                
 
459
                /// <summary>
 
460
                /// Gets extension objects registered for a type extension point.
 
461
                /// </summary>
 
462
                /// <returns>
 
463
                /// A list of objects
 
464
                /// </returns>
 
465
                /// <remarks>
 
466
                /// The type argument of this generic method is the type that defines
 
467
                /// the extension point.
 
468
                /// </remarks>
 
469
                public T[] GetExtensionObjects<T> ()
 
470
                {
 
471
                        return GetExtensionObjects<T> (true);
 
472
                }
 
473
                
 
474
                /// <summary>
 
475
                /// Gets extension objects registered for a type extension point.
 
476
                /// </summary>
 
477
                /// <param name="instanceType">
 
478
                /// Type defining the extension point
 
479
                /// </param>
 
480
                /// <param name="reuseCachedInstance">
 
481
                /// When set to True, it will return instances created in previous calls.
 
482
                /// </param>
 
483
                /// <returns>
 
484
                /// A list of extension objects.
 
485
                /// </returns>
 
486
                public object[] GetExtensionObjects (Type instanceType, bool reuseCachedInstance)
 
487
                {
 
488
                        string path = AddinEngine.GetAutoTypeExtensionPoint (instanceType);
 
489
                        if (path == null)
 
490
                                return (object[]) Array.CreateInstance (instanceType, 0);
 
491
                        return GetExtensionObjects (path, instanceType, reuseCachedInstance);
 
492
                }
 
493
                
 
494
                /// <summary>
 
495
                /// Gets extension objects registered for a type extension point.
 
496
                /// </summary>
 
497
                /// <param name="reuseCachedInstance">
 
498
                /// When set to True, it will return instances created in previous calls.
 
499
                /// </param>
 
500
                /// <returns>
 
501
                /// A list of extension objects.
 
502
                /// </returns>
 
503
                /// <remarks>
 
504
                /// The type argument of this generic method is the type that defines
 
505
                /// the extension point.
 
506
                /// </remarks>
 
507
                public T[] GetExtensionObjects<T> (bool reuseCachedInstance)
 
508
                {
 
509
                        string path = AddinEngine.GetAutoTypeExtensionPoint (typeof(T));
 
510
                        if (path == null)
 
511
                                return new T[0];
 
512
                        return GetExtensionObjects<T> (path, reuseCachedInstance);
 
513
                }
 
514
                
 
515
                /// <summary>
 
516
                /// Gets extension objects registered in a path
 
517
                /// </summary>
 
518
                /// <param name="path">
 
519
                /// An extension path.
 
520
                /// </param>
 
521
                /// <returns>
 
522
                /// An array of objects registered in the path.
 
523
                /// </returns>
 
524
                /// <remarks>
 
525
                /// This method can only be used if all nodes in the provided extension path
 
526
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
527
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
528
                /// method for each node.
 
529
                /// </remarks>
 
530
                public object[] GetExtensionObjects (string path)
 
531
                {
 
532
                        return GetExtensionObjects (path, typeof(object), true);
 
533
                }
 
534
                
 
535
                /// <summary>
 
536
                /// Gets extension objects registered in a path.
 
537
                /// </summary>
 
538
                /// <param name="path">
 
539
                /// An extension path.
 
540
                /// </param>
 
541
                /// <param name="reuseCachedInstance">
 
542
                /// When set to True, it will return instances created in previous calls.
 
543
                /// </param>
 
544
                /// <returns>
 
545
                /// An array of objects registered in the path.
 
546
                /// </returns>
 
547
                /// <remarks>
 
548
                /// This method can only be used if all nodes in the provided extension path
 
549
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
550
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
551
                /// method for each node (or TypeExtensionNode.GetInstance() if
 
552
                /// reuseCachedInstance is set to true)
 
553
                /// </remarks>
 
554
                public object[] GetExtensionObjects (string path, bool reuseCachedInstance)
 
555
                {
 
556
                        return GetExtensionObjects (path, typeof(object), reuseCachedInstance);
 
557
                }
 
558
                
 
559
                /// <summary>
 
560
                /// Gets extension objects registered in a path.
 
561
                /// </summary>
 
562
                /// <param name="path">
 
563
                /// An extension path.
 
564
                /// </param>
 
565
                /// <param name="arrayElementType">
 
566
                /// Type of the return array elements.
 
567
                /// </param>
 
568
                /// <returns>
 
569
                /// An array of objects registered in the path.
 
570
                /// </returns>
 
571
                /// <remarks>
 
572
                /// This method can only be used if all nodes in the provided extension path
 
573
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
574
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
575
                /// method for each node.
 
576
                /// 
 
577
                /// An InvalidOperationException exception is thrown if one of the found
 
578
                /// objects is not a subclass of the provided type.
 
579
                /// </remarks>
 
580
                public object[] GetExtensionObjects (string path, Type arrayElementType)
 
581
                {
 
582
                        return GetExtensionObjects (path, arrayElementType, true);
 
583
                }
 
584
                
 
585
                /// <summary>
 
586
                /// Gets extension objects registered in a path.
 
587
                /// </summary>
 
588
                /// <param name="path">
 
589
                /// An extension path.
 
590
                /// </param>
 
591
                /// <returns>
 
592
                /// An array of objects registered in the path.
 
593
                /// </returns>
 
594
                /// <remarks>
 
595
                /// This method can only be used if all nodes in the provided extension path
 
596
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
597
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
598
                /// method for each node.
 
599
                /// 
 
600
                /// An InvalidOperationException exception is thrown if one of the found
 
601
                /// objects is not a subclass of the provided type.
 
602
                /// </remarks>
 
603
                public T[] GetExtensionObjects<T> (string path)
 
604
                {
 
605
                        return GetExtensionObjects<T> (path, true);
 
606
                }
 
607
                
 
608
                /// <summary>
 
609
                /// Gets extension objects registered in a path.
 
610
                /// </summary>
 
611
                /// <param name="path">
 
612
                /// An extension path.
 
613
                /// </param>
 
614
                /// <param name="reuseCachedInstance">
 
615
                /// When set to True, it will return instances created in previous calls.
 
616
                /// </param>
 
617
                /// <returns>
 
618
                /// An array of objects registered in the path.
 
619
                /// </returns>
 
620
                /// <remarks>
 
621
                /// This method can only be used if all nodes in the provided extension path
 
622
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
623
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
624
                /// method for each node (or TypeExtensionNode.GetInstance() if
 
625
                /// reuseCachedInstance is set to true).
 
626
                /// 
 
627
                /// An InvalidOperationException exception is thrown if one of the found
 
628
                /// objects is not a subclass of the provided type.
 
629
                /// </remarks>
 
630
                public T[] GetExtensionObjects<T> (string path, bool reuseCachedInstance)
 
631
                {
 
632
                        ExtensionNode node = GetExtensionNode (path);
 
633
                        if (node == null)
 
634
                                throw new InvalidOperationException ("Extension node not found in path: " + path);
 
635
                        return node.GetChildObjects<T> (reuseCachedInstance);
 
636
                }
 
637
                
 
638
                /// <summary>
 
639
                /// Gets extension objects registered in a path.
 
640
                /// </summary>
 
641
                /// <param name="path">
 
642
                /// An extension path.
 
643
                /// </param>
 
644
                /// <param name="arrayElementType">
 
645
                /// Type of the return array elements.
 
646
                /// </param>
 
647
                /// <param name="reuseCachedInstance">
 
648
                /// When set to True, it will return instances created in previous calls.
 
649
                /// </param>
 
650
                /// <returns>
 
651
                /// An array of objects registered in the path.
 
652
                /// </returns>
 
653
                /// <remarks>
 
654
                /// This method can only be used if all nodes in the provided extension path
 
655
                /// are of type Mono.Addins.TypeExtensionNode. The returned array is composed
 
656
                /// by all objects created by calling the TypeExtensionNode.CreateInstance()
 
657
                /// method for each node (or TypeExtensionNode.GetInstance() if
 
658
                /// reuseCachedInstance is set to true).
 
659
                /// 
 
660
                /// An InvalidOperationException exception is thrown if one of the found
 
661
                /// objects is not a subclass of the provided type.
 
662
                /// </remarks>
 
663
                public object[] GetExtensionObjects (string path, Type arrayElementType, bool reuseCachedInstance)
 
664
                {
 
665
                        ExtensionNode node = GetExtensionNode (path);
 
666
                        if (node == null)
 
667
                                throw new InvalidOperationException ("Extension node not found in path: " + path);
 
668
                        return node.GetChildObjects (arrayElementType, reuseCachedInstance);
 
669
                }
 
670
                
 
671
                /// <summary>
 
672
                /// Register a listener of extension node changes.
 
673
                /// </summary>
 
674
                /// <param name="path">
 
675
                /// Path of the node.
 
676
                /// </param>
 
677
                /// <param name="handler">
 
678
                /// A handler method.
 
679
                /// </param>
 
680
                /// <remarks>
 
681
                /// Hosts can call this method to be subscribed to an extension change
 
682
                /// event for a specific path. The event will be fired once for every
 
683
                /// individual node change. The event arguments include the change type
 
684
                /// (Add or Remove) and the extension node added or removed.
 
685
                /// 
 
686
                /// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
 
687
                /// </remarks>
 
688
                public void AddExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
 
689
                {
 
690
                        ExtensionNode node = GetExtensionNode (path);
 
691
                        if (node == null)
 
692
                                throw new InvalidOperationException ("Extension node not found in path: " + path);
 
693
                        node.ExtensionNodeChanged += handler;
 
694
                }
 
695
                
 
696
                /// <summary>
 
697
                /// Unregister a listener of extension node changes.
 
698
                /// </summary>
 
699
                /// <param name="path">
 
700
                /// Path of the node.
 
701
                /// </param>
 
702
                /// <param name="handler">
 
703
                /// A handler method.
 
704
                /// </param>
 
705
                /// <remarks>
 
706
                /// This method unregisters a delegate from the node change event of a path.
 
707
                /// </remarks>
 
708
                public void RemoveExtensionNodeHandler (string path, ExtensionNodeEventHandler handler)
 
709
                {
 
710
                        ExtensionNode node = GetExtensionNode (path);
 
711
                        if (node == null)
 
712
                                throw new InvalidOperationException ("Extension node not found in path: " + path);
 
713
                        node.ExtensionNodeChanged -= handler;
 
714
                }
 
715
                
 
716
                /// <summary>
 
717
                /// Register a listener of extension node changes.
 
718
                /// </summary>
 
719
                /// <param name="instanceType">
 
720
                /// Type defining the extension point
 
721
                /// </param>
 
722
                /// <param name="handler">
 
723
                /// A handler method.
 
724
                /// </param>
 
725
                /// <remarks>
 
726
                /// Hosts can call this method to be subscribed to an extension change
 
727
                /// event for a specific type extension point. The event will be fired once for every
 
728
                /// individual node change. The event arguments include the change type
 
729
                /// (Add or Remove) and the extension node added or removed.
 
730
                /// 
 
731
                /// NOTE: The handler will be called for all nodes existing in the path at the moment of registration.
 
732
                /// </remarks>
 
733
                public void AddExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
 
734
                {
 
735
                        string path = AddinEngine.GetAutoTypeExtensionPoint (instanceType);
 
736
                        if (path == null)
 
737
                                throw new InvalidOperationException ("Type '" + instanceType + "' not bound to an extension point.");
 
738
                        AddExtensionNodeHandler (path, handler);
 
739
                }
 
740
                
 
741
                /// <summary>
 
742
                /// Unregister a listener of extension node changes.
 
743
                /// </summary>
 
744
                /// <param name="instanceType">
 
745
                /// Type defining the extension point
 
746
                /// </param>
 
747
                /// <param name="handler">
 
748
                /// A handler method.
 
749
                /// </param>
 
750
                public void RemoveExtensionNodeHandler (Type instanceType, ExtensionNodeEventHandler handler)
 
751
                {
 
752
                        string path = AddinEngine.GetAutoTypeExtensionPoint (instanceType);
 
753
                        if (path == null)
 
754
                                throw new InvalidOperationException ("Type '" + instanceType + "' not bound to an extension point.");
 
755
                        RemoveExtensionNodeHandler (path, handler);
 
756
                }
 
757
                
 
758
                void OnConditionChanged (object s, EventArgs a)
 
759
                {
 
760
                        ConditionType cond = (ConditionType) s;
 
761
                        NotifyConditionChanged (cond);
 
762
                }
 
763
                
 
764
                internal void NotifyConditionChanged (ConditionType cond)
 
765
                {
 
766
                        try {
 
767
                                fireEvents = true;
 
768
                                
 
769
                                ConditionInfo info = (ConditionInfo) conditionTypes [cond.Id];
 
770
                                if (info != null && info.BoundConditions != null) {
 
771
                                        Hashtable parentsToNotify = new Hashtable ();
 
772
                                        foreach (BaseCondition c in info.BoundConditions) {
 
773
                                                ArrayList nodeList = (ArrayList) conditionsToNodes [c];
 
774
                                                if (nodeList != null) {
 
775
                                                        foreach (TreeNode node in nodeList)
 
776
                                                                parentsToNotify [node.Parent] = null;
 
777
                                                }
 
778
                                        }
 
779
                                        foreach (TreeNode node in parentsToNotify.Keys) {
 
780
                                                if (node.NotifyChildrenChanged ())
 
781
                                                        NotifyExtensionsChanged (new ExtensionEventArgs (node.GetPath ()));
 
782
                                        }
 
783
                                }
 
784
                        }
 
785
                        finally {
 
786
                                fireEvents = false;
 
787
                        }
 
788
 
 
789
                        // Notify child contexts
 
790
                        lock (conditionTypes) {
 
791
                                if (childContexts != null) {
 
792
                                        CleanDisposedChildContexts ();
 
793
                                        foreach (WeakReference wref in childContexts) {
 
794
                                                ExtensionContext ctx = wref.Target as ExtensionContext;
 
795
                                                if (ctx != null)
 
796
                                                        ctx.NotifyConditionChanged (cond);
 
797
                                        }
 
798
                                }
 
799
                        }
 
800
                }
 
801
                
 
802
 
 
803
                internal void NotifyExtensionsChanged (ExtensionEventArgs args)
 
804
                {
 
805
                        if (!fireEvents)
 
806
                                return;
 
807
 
 
808
                        if (ExtensionChanged != null)
 
809
                                ExtensionChanged (this, args);
 
810
                }
 
811
                
 
812
                internal void NotifyAddinLoaded (RuntimeAddin ad)
 
813
                {
 
814
                        tree.NotifyAddinLoaded (ad, true);
 
815
 
 
816
                        lock (conditionTypes) {
 
817
                                if (childContexts != null) {
 
818
                                        CleanDisposedChildContexts ();
 
819
                                        foreach (WeakReference wref in childContexts) {
 
820
                                                ExtensionContext ctx = wref.Target as ExtensionContext;
 
821
                                                if (ctx != null)
 
822
                                                        ctx.NotifyAddinLoaded (ad);
 
823
                                        }
 
824
                                }
 
825
                        }
 
826
                }
 
827
                
 
828
                internal void CreateExtensionPoint (ExtensionPoint ep)
 
829
                {
 
830
                        TreeNode node = tree.GetNode (ep.Path, true);
 
831
                        if (node.ExtensionPoint == null) {
 
832
                                node.ExtensionPoint = ep;
 
833
                                node.ExtensionNodeSet = ep.NodeSet;
 
834
                        }
 
835
                }
 
836
                
 
837
                internal void ActivateAddinExtensions (string id)
 
838
                {
 
839
                        // Looks for loaded extension points which are extended by the provided
 
840
                        // add-in, and adds the new nodes
 
841
                        
 
842
                        try {
 
843
                                fireEvents = true;
 
844
                                
 
845
                                Addin addin = AddinEngine.Registry.GetAddin (id);
 
846
                                if (addin == null) {
 
847
                                        AddinEngine.ReportError ("Required add-in not found", id, null, false);
 
848
                                        return;
 
849
                                }
 
850
                                // Take note that this add-in has been enabled at run-time
 
851
                                // Needed because loaded add-in descriptions may not include this add-in. 
 
852
                                RegisterRuntimeEnabledAddin (id);
 
853
                                
 
854
                                // Look for loaded extension points
 
855
                                Hashtable eps = new Hashtable ();
 
856
                                ArrayList newExtensions = new ArrayList ();
 
857
                                foreach (ModuleDescription mod in addin.Description.AllModules) {
 
858
                                        foreach (Extension ext in mod.Extensions) {
 
859
                                                if (!newExtensions.Contains (ext.Path))
 
860
                                                        newExtensions.Add (ext.Path);
 
861
                                                ExtensionPoint ep = tree.FindLoadedExtensionPoint (ext.Path);
 
862
                                                if (ep != null && !eps.Contains (ep))
 
863
                                                        eps.Add (ep, ep);
 
864
                                        }
 
865
                                }
 
866
                                
 
867
                                // Add the new nodes
 
868
                                ArrayList loadedNodes = new ArrayList ();
 
869
                                foreach (ExtensionPoint ep in eps.Keys) {
 
870
                                        ExtensionLoadData data = GetAddinExtensions (id, ep);
 
871
                                        if (data != null) {
 
872
                                                foreach (Extension ext in data.Extensions) {
 
873
                                                        TreeNode node = GetNode (ext.Path);
 
874
                                                        if (node != null && node.ExtensionNodeSet != null) {
 
875
                                                                if (node.ChildrenLoaded)
 
876
                                                                        LoadModuleExtensionNodes (ext, data.AddinId, node.ExtensionNodeSet, loadedNodes);
 
877
                                                        }
 
878
                                                        else
 
879
                                                                AddinEngine.ReportError ("Extension node not found or not extensible: " + ext.Path, id, null, false);
 
880
                                                }
 
881
                                        }
 
882
                                }
 
883
                                
 
884
                                // Call the OnAddinLoaded method on nodes, if the add-in is already loaded
 
885
                                foreach (TreeNode nod in loadedNodes)
 
886
                                        nod.ExtensionNode.OnAddinLoaded ();
 
887
                                
 
888
                                // Global extension change event. Other events are fired by LoadModuleExtensionNodes.
 
889
                                // The event is called for all extensions, even for those not loaded. This is for coherence,
 
890
                                // although that something that it doesn't make much sense to do (subcribing the ExtensionChanged
 
891
                                // event without first getting the list of nodes that may change).
 
892
                                foreach (string newExt in newExtensions)
 
893
                                        NotifyExtensionsChanged (new ExtensionEventArgs (newExt));
 
894
                        }
 
895
                        finally {
 
896
                                fireEvents = false;
 
897
                        }
 
898
                        // Do the same in child contexts
 
899
                        
 
900
                        lock (conditionTypes) {
 
901
                                if (childContexts != null) {
 
902
                                        CleanDisposedChildContexts ();
 
903
                                        foreach (WeakReference wref in childContexts) {
 
904
                                                ExtensionContext ctx = wref.Target as ExtensionContext;
 
905
                                                if (ctx != null)
 
906
                                                        ctx.ActivateAddinExtensions (id);
 
907
                                        }
 
908
                                }
 
909
                        }
 
910
                }
 
911
                
 
912
                internal void RemoveAddinExtensions (string id)
 
913
                {
 
914
                        try {
 
915
                                // Registers this add-in as disabled, so from now on extension from this
 
916
                                // add-in will be ignored
 
917
                                RegisterRuntimeDisabledAddin (id);
 
918
                                
 
919
                                fireEvents = true;
 
920
 
 
921
                                // This method removes all extension nodes added by the add-in
 
922
                                // Get all nodes created by the addin
 
923
                                ArrayList list = new ArrayList ();
 
924
                                tree.FindAddinNodes (id, list);
 
925
                                
 
926
                                // Remove each node and notify the change
 
927
                                foreach (TreeNode node in list) {
 
928
                                        if (node.ExtensionNode == null) {
 
929
                                                // It's an extension point. Just remove it, no notifications are needed
 
930
                                                node.Remove ();
 
931
                                        }
 
932
                                        else {
 
933
                                                node.ExtensionNode.OnAddinUnloaded ();
 
934
                                                node.Remove ();
 
935
                                        }
 
936
                                }
 
937
                                
 
938
                                // Notify global extension point changes.
 
939
                                // The event is called for all extensions, even for those not loaded. This is for coherence,
 
940
                                // although that something that it doesn't make much sense to do (subcribing the ExtensionChanged
 
941
                                // event without first getting the list of nodes that may change).
 
942
                                
 
943
                                // We get the runtime add-in because the add-in may already have been deleted from the registry
 
944
                                RuntimeAddin addin = AddinEngine.GetAddin (id);
 
945
                                if (addin != null) {
 
946
                                        ArrayList paths = new ArrayList ();
 
947
                                        // Using addin.Module.ParentAddinDescription here because addin.Addin.Description may not
 
948
                                        // have a valid reference (the description is lazy loaded and may already have been removed from the registry)
 
949
                                        foreach (ModuleDescription mod in addin.Module.ParentAddinDescription.AllModules) {
 
950
                                                foreach (Extension ext in mod.Extensions) {
 
951
                                                        if (!paths.Contains (ext.Path))
 
952
                                                                paths.Add (ext.Path);
 
953
                                                }
 
954
                                        }
 
955
                                        foreach (string path in paths)
 
956
                                                NotifyExtensionsChanged (new ExtensionEventArgs (path));
 
957
                                }                               
 
958
                        } finally {
 
959
                                fireEvents = false;
 
960
                        }
 
961
                }
 
962
                
 
963
                void RegisterRuntimeDisabledAddin (string addinId)
 
964
                {
 
965
                        if (runTimeDisabledAddins == null)
 
966
                                runTimeDisabledAddins = new ArrayList ();
 
967
                        if (!runTimeDisabledAddins.Contains (addinId))
 
968
                                runTimeDisabledAddins.Add (addinId);
 
969
                        
 
970
                        if (runTimeEnabledAddins != null)
 
971
                                runTimeEnabledAddins.Remove (addinId);
 
972
                }
 
973
                
 
974
                void RegisterRuntimeEnabledAddin (string addinId)
 
975
                {
 
976
                        if (runTimeEnabledAddins == null)
 
977
                                runTimeEnabledAddins = new ArrayList ();
 
978
                        if (!runTimeEnabledAddins.Contains (addinId))
 
979
                                runTimeEnabledAddins.Add (addinId);
 
980
                        
 
981
                        if (runTimeDisabledAddins != null)
 
982
                                runTimeDisabledAddins.Remove (addinId);
 
983
                }
 
984
                
 
985
                internal ICollection GetAddinsForPath (string path, List<string> col)
 
986
                {
 
987
                        ArrayList newlist = null;
 
988
                        
 
989
                        // Always consider add-ins which have been enabled at runtime since
 
990
                        // they may contain extensioin for this path.
 
991
                        // Ignore addins disabled at run-time.
 
992
                        
 
993
                        if (runTimeEnabledAddins != null && runTimeEnabledAddins.Count > 0) {
 
994
                                newlist = new ArrayList ();
 
995
                                newlist.AddRange (col);
 
996
                                foreach (string s in runTimeEnabledAddins)
 
997
                                        if (!newlist.Contains (s))
 
998
                                                newlist.Add (s);
 
999
                        }
 
1000
                        
 
1001
                        if (runTimeDisabledAddins != null && runTimeDisabledAddins.Count > 0) {
 
1002
                                if (newlist == null) {
 
1003
                                        newlist = new ArrayList ();
 
1004
                                        newlist.AddRange (col);
 
1005
                                }
 
1006
                                foreach (string s in runTimeDisabledAddins)
 
1007
                                        newlist.Remove (s);
 
1008
                        }
 
1009
                        
 
1010
                        return newlist != null ? (ICollection)newlist : (ICollection)col;
 
1011
                }
 
1012
                
 
1013
                // Load the extension nodes at the specified path. If the path
 
1014
                // contains extension nodes implemented in an add-in which is
 
1015
                // not loaded, the add-in will be automatically loaded
 
1016
                
 
1017
                internal void LoadExtensions (string requestedExtensionPath)
 
1018
                {
 
1019
                        TreeNode node = GetNode (requestedExtensionPath);
 
1020
                        if (node == null)
 
1021
                                throw new InvalidOperationException ("Extension point not defined: " + requestedExtensionPath);
 
1022
 
 
1023
                        ExtensionPoint ep = node.ExtensionPoint;
 
1024
 
 
1025
                        if (ep != null) {
 
1026
                        
 
1027
                                // Collect extensions to be loaded from add-ins. Before loading the extensions,
 
1028
                                // they must be sorted, that's why loading is split in two steps (collecting + loading).
 
1029
                                
 
1030
                                ArrayList loadData = new ArrayList ();
 
1031
                                
 
1032
                                foreach (string addin in GetAddinsForPath (ep.Path, ep.Addins)) {
 
1033
                                        ExtensionLoadData ed = GetAddinExtensions (addin, ep);
 
1034
                                        if (ed != null) {
 
1035
                                                // Insert the addin data taking into account dependencies.
 
1036
                                                // An add-in must be processed after all its dependencies.
 
1037
                                                bool added = false;
 
1038
                                                for (int n=0; n<loadData.Count; n++) {
 
1039
                                                        ExtensionLoadData other = (ExtensionLoadData) loadData [n];
 
1040
                                                        if (AddinEngine.Registry.AddinDependsOn (other.AddinId, ed.AddinId)) {
 
1041
                                                                loadData.Insert (n, ed);
 
1042
                                                                added = true;
 
1043
                                                                break;
 
1044
                                                        }
 
1045
                                                }
 
1046
                                                if (!added)
 
1047
                                                        loadData.Add (ed);
 
1048
                                        }
 
1049
                                }
 
1050
                                
 
1051
                                // Now load the extensions
 
1052
                                
 
1053
                                ArrayList loadedNodes = new ArrayList ();
 
1054
                                foreach (ExtensionLoadData data in loadData) {
 
1055
                                        foreach (Extension ext in data.Extensions) {
 
1056
                                                TreeNode cnode = GetNode (ext.Path);
 
1057
                                                if (cnode != null && cnode.ExtensionNodeSet != null)
 
1058
                                                        LoadModuleExtensionNodes (ext, data.AddinId, cnode.ExtensionNodeSet, loadedNodes);
 
1059
                                                else
 
1060
                                                        AddinEngine.ReportError ("Extension node not found or not extensible: " + ext.Path, data.AddinId, null, false);
 
1061
                                        }
 
1062
                                }
 
1063
                                // Call the OnAddinLoaded method on nodes, if the add-in is already loaded
 
1064
                                foreach (TreeNode nod in loadedNodes)
 
1065
                                        nod.ExtensionNode.OnAddinLoaded ();
 
1066
 
 
1067
                                NotifyExtensionsChanged (new ExtensionEventArgs (requestedExtensionPath));
 
1068
                        }
 
1069
                }
 
1070
                
 
1071
                ExtensionLoadData GetAddinExtensions (string id, ExtensionPoint ep)
 
1072
                {
 
1073
                        Addin pinfo = null;
 
1074
 
 
1075
                        // Root add-ins are not returned by GetInstalledAddin.
 
1076
                        RuntimeAddin addin = AddinEngine.GetAddin (id);
 
1077
                        if (addin != null)
 
1078
                                pinfo = addin.Addin;
 
1079
                        else
 
1080
                                pinfo = AddinEngine.Registry.GetAddin (id);
 
1081
                        
 
1082
                        if (pinfo == null) {
 
1083
                                AddinEngine.ReportError ("Required add-in not found", id, null, false);
 
1084
                                return null;
 
1085
                        }
 
1086
                        if (!pinfo.Enabled || pinfo.Version != Addin.GetIdVersion (id))
 
1087
                                return null;
 
1088
                                
 
1089
                        // Loads extensions defined in each module
 
1090
                        
 
1091
                        ExtensionLoadData data = null;
 
1092
                        AddinDescription conf = pinfo.Description;
 
1093
                        GetAddinExtensions (conf.MainModule, id, ep, ref data);
 
1094
                        
 
1095
                        foreach (ModuleDescription module in conf.OptionalModules) {
 
1096
                                if (CheckOptionalAddinDependencies (conf, module))
 
1097
                                        GetAddinExtensions (module, id, ep, ref data);
 
1098
                        }
 
1099
                        if (data != null)
 
1100
                                data.Extensions.Sort ();
 
1101
 
 
1102
                        return data;
 
1103
                }
 
1104
                
 
1105
                void GetAddinExtensions (ModuleDescription module, string addinId, ExtensionPoint ep, ref ExtensionLoadData data)
 
1106
                {
 
1107
                        string basePath = ep.Path + "/";
 
1108
                        
 
1109
                        foreach (Extension extension in module.Extensions) {
 
1110
                                if (extension.Path == ep.Path || extension.Path.StartsWith (basePath)) {
 
1111
                                        if (data == null) {
 
1112
                                                data = new ExtensionLoadData ();
 
1113
                                                data.AddinId = addinId;
 
1114
                                                data.Extensions = new ArrayList ();
 
1115
                                        }
 
1116
                                        data.Extensions.Add (extension);
 
1117
                                }
 
1118
                        }
 
1119
                }
 
1120
                
 
1121
                void LoadModuleExtensionNodes (Extension extension, string addinId, ExtensionNodeSet nset, ArrayList loadedNodes)
 
1122
                {
 
1123
                        // Now load the extensions
 
1124
                        ArrayList addedNodes = new ArrayList ();
 
1125
                        tree.LoadExtension (addinId, extension, addedNodes);
 
1126
                        
 
1127
                        RuntimeAddin ad = AddinEngine.GetAddin (addinId);
 
1128
                        if (ad != null) {
 
1129
                                foreach (TreeNode nod in addedNodes) {
 
1130
                                        // Don't call OnAddinLoaded here. Do it when the entire extension point has been loaded.
 
1131
                                        if (nod.ExtensionNode != null)
 
1132
                                                loadedNodes.Add (nod);
 
1133
                                }
 
1134
                        }
 
1135
                }
 
1136
                
 
1137
                bool CheckOptionalAddinDependencies (AddinDescription conf, ModuleDescription module)
 
1138
                {
 
1139
                        foreach (Dependency dep in module.Dependencies) {
 
1140
                                AddinDependency pdep = dep as AddinDependency;
 
1141
                                if (pdep != null) {
 
1142
                                        Addin pinfo = AddinEngine.Registry.GetAddin (Addin.GetFullId (conf.Namespace, pdep.AddinId, pdep.Version));
 
1143
                                        if (pinfo == null || !pinfo.Enabled)
 
1144
                                                return false;
 
1145
                                }
 
1146
                        }
 
1147
                        return true;
 
1148
                }
 
1149
 
 
1150
                
 
1151
                TreeNode GetNode (string path)
 
1152
                {
 
1153
                        TreeNode node = tree.GetNode (path);
 
1154
                        if (node != null || parentContext == null)
 
1155
                                return node;
 
1156
                        
 
1157
                        TreeNode supNode = parentContext.tree.GetNode (path);
 
1158
                        if (supNode == null)
 
1159
                                return null;
 
1160
                        
 
1161
                        if (path.StartsWith ("/"))
 
1162
                                path = path.Substring (1);
 
1163
 
 
1164
                        string[] parts = path.Split ('/');
 
1165
                        TreeNode srcNode = parentContext.tree;
 
1166
                        TreeNode dstNode = tree;
 
1167
 
 
1168
                        foreach (string part in parts) {
 
1169
                                
 
1170
                                // Look for the node in the source tree
 
1171
                                
 
1172
                                int i = srcNode.Children.IndexOfNode (part);
 
1173
                                if (i != -1)
 
1174
                                        srcNode = srcNode.Children [i];
 
1175
                                else
 
1176
                                        return null;
 
1177
 
 
1178
                                // Now get the node in the target tree
 
1179
                                
 
1180
                                int j = dstNode.Children.IndexOfNode (part);
 
1181
                                if (j != -1) {
 
1182
                                        dstNode = dstNode.Children [j];
 
1183
                                }
 
1184
                                else {
 
1185
                                        // Create if not found
 
1186
                                        TreeNode newNode = new TreeNode (AddinEngine, part);
 
1187
                                        dstNode.AddChildNode (newNode);
 
1188
                                        dstNode = newNode;
 
1189
                                        
 
1190
                                        // Copy extension data
 
1191
                                        dstNode.ExtensionNodeSet = srcNode.ExtensionNodeSet;
 
1192
                                        dstNode.ExtensionPoint = srcNode.ExtensionPoint;
 
1193
                                        dstNode.Condition = srcNode.Condition;
 
1194
                                        
 
1195
                                        if (dstNode.Condition != null)
 
1196
                                                RegisterNodeCondition (dstNode, dstNode.Condition);
 
1197
                                }
 
1198
                        }
 
1199
                        
 
1200
                        return dstNode;
 
1201
                }
 
1202
                
 
1203
                internal bool FindExtensionPathByType (IProgressStatus monitor, Type type, string nodeName, out string path, out string pathNodeName)
 
1204
                {
 
1205
                        return tree.FindExtensionPathByType (monitor, type, nodeName, out path, out pathNodeName);
 
1206
                }
 
1207
        }
 
1208
        
 
1209
        class ConditionInfo
 
1210
        {
 
1211
                public object CondType;
 
1212
                public ArrayList BoundConditions;
 
1213
        }
 
1214
 
 
1215
        
 
1216
        /// <summary>
 
1217
        /// Delegate to be used in extension point subscriptions
 
1218
        /// </summary>
 
1219
        public delegate void ExtensionEventHandler (object sender, ExtensionEventArgs args);
 
1220
        
 
1221
        /// <summary>
 
1222
        /// Delegate to be used in extension point subscriptions
 
1223
        /// </summary>
 
1224
        public delegate void ExtensionNodeEventHandler (object sender, ExtensionNodeEventArgs args);
 
1225
        
 
1226
        /// <summary>
 
1227
        /// Arguments for extension events.
 
1228
        /// </summary>
 
1229
        public class ExtensionEventArgs: EventArgs
 
1230
        {
 
1231
                string path;
 
1232
                
 
1233
                internal ExtensionEventArgs ()
 
1234
                {
 
1235
                }
 
1236
                
 
1237
                /// <summary>
 
1238
                /// Creates a new instance.
 
1239
                /// </summary>
 
1240
                /// <param name="path">
 
1241
                /// Path of the extension node that has changed.
 
1242
                /// </param>
 
1243
                public ExtensionEventArgs (string path)
 
1244
                {
 
1245
                        this.path = path;
 
1246
                }
 
1247
                
 
1248
                /// <summary>
 
1249
                /// Path of the extension node that has changed.
 
1250
                /// </summary>
 
1251
                public virtual string Path {
 
1252
                        get { return path; }
 
1253
                }
 
1254
                
 
1255
                /// <summary>
 
1256
                /// Checks if a path has changed.
 
1257
                /// </summary>
 
1258
                /// <param name="pathToCheck">
 
1259
                /// An extension path.
 
1260
                /// </param>
 
1261
                /// <returns>
 
1262
                /// 'true' if the path is affected by the extension change event.
 
1263
                /// </returns>
 
1264
                /// <remarks>
 
1265
                /// Checks if the specified path or any of its children paths is affected by the extension change event.
 
1266
                /// </remarks>
 
1267
                public bool PathChanged (string pathToCheck)
 
1268
                {
 
1269
                        if (pathToCheck.EndsWith ("/"))
 
1270
                                return path.StartsWith (pathToCheck);
 
1271
                        else
 
1272
                                return path.StartsWith (pathToCheck) && (pathToCheck.Length == path.Length || path [pathToCheck.Length] == '/');
 
1273
                }
 
1274
        }
 
1275
        
 
1276
        /// <summary>
 
1277
        /// Arguments for extension node events.
 
1278
        /// </summary>
 
1279
        public class ExtensionNodeEventArgs: ExtensionEventArgs
 
1280
        {
 
1281
                ExtensionNode node;
 
1282
                ExtensionChange change;
 
1283
                
 
1284
                /// <summary>
 
1285
                /// Creates a new instance
 
1286
                /// </summary>
 
1287
                /// <param name="change">
 
1288
                /// Type of change.
 
1289
                /// </param>
 
1290
                /// <param name="node">
 
1291
                /// Node that has been added or removed.
 
1292
                /// </param>
 
1293
                public ExtensionNodeEventArgs (ExtensionChange change, ExtensionNode node)
 
1294
                {
 
1295
                        this.node = node;
 
1296
                        this.change = change;
 
1297
                }
 
1298
                
 
1299
                /// <summary>
 
1300
                /// Path of the extension that changed.
 
1301
                /// </summary>
 
1302
                public override string Path {
 
1303
                        get { return node.Path; }
 
1304
                }
 
1305
                
 
1306
                /// <summary>
 
1307
                /// Type of change.
 
1308
                /// </summary>
 
1309
                public ExtensionChange Change {
 
1310
                        get { return change; }
 
1311
                }
 
1312
                
 
1313
                /// <summary>
 
1314
                /// Node that has been added or removed.
 
1315
                /// </summary>
 
1316
                public ExtensionNode ExtensionNode {
 
1317
                        get { return node; }
 
1318
                }
 
1319
                
 
1320
                /// <summary>
 
1321
                /// Extension object that has been added or removed.
 
1322
                /// </summary>
 
1323
                public object ExtensionObject {
 
1324
                        get {
 
1325
                                InstanceExtensionNode tnode = node as InstanceExtensionNode;
 
1326
                                if (tnode == null)
 
1327
                                        throw new InvalidOperationException ("Node is not an InstanceExtensionNode");
 
1328
                                return tnode.GetInstance (); 
 
1329
                        }
 
1330
                }
 
1331
        }
 
1332
        
 
1333
        /// <summary>
 
1334
        /// Type of change in an extension change event.
 
1335
        /// </summary>
 
1336
        public enum ExtensionChange
 
1337
        {
 
1338
                /// <summary>
 
1339
                /// An extension node has been added.
 
1340
                /// </summary>
 
1341
                Add,
 
1342
                
 
1343
                /// <summary>
 
1344
                /// An extension node has been removed.
 
1345
                /// </summary>
 
1346
                Remove
 
1347
        }
 
1348
 
 
1349
        
 
1350
        internal class ExtensionLoadData
 
1351
        {
 
1352
                public string AddinId;
 
1353
                public ArrayList Extensions;
 
1354
        }
 
1355
}