7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
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:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
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.
31
using System.Collections;
33
using System.Reflection;
34
using Mono.Addins.Description;
38
public class ExtensionNode
42
ExtensionNodeList childNodes;
45
ExtensionNodeType nodeType;
46
event ExtensionNodeEventHandler extensionNodeChanged;
49
get { return treeNode != null ? treeNode.Id : string.Empty; }
53
get { return treeNode != null ? treeNode.GetPath () : string.Empty; }
56
public ExtensionNode Parent {
58
if (treeNode != null && treeNode.Parent != null)
59
return treeNode.Parent.ExtensionNode;
65
public ExtensionContext ExtensionContext {
66
get { return treeNode.Context; }
70
get { return !Id.StartsWith (ExtensionTree.AutoIdPrefix); }
73
internal void SetTreeNode (TreeNode node)
78
internal void SetData (string plugid, ExtensionNodeType nodeType)
80
this.addinId = plugid;
81
this.nodeType = nodeType;
84
internal string AddinId {
85
get { return addinId; }
88
internal TreeNode TreeNode {
89
get { return treeNode; }
92
public RuntimeAddin Addin {
94
if (addin == null && addinId != null) {
95
if (!AddinManager.SessionService.IsAddinLoaded (addinId))
96
AddinManager.SessionService.LoadAddin (null, addinId, true);
97
addin = AddinManager.SessionService.GetAddin (addinId);
100
throw new InvalidOperationException ("Add-in '" + addinId + "' could not be loaded.");
105
public event ExtensionNodeEventHandler ExtensionNodeChanged {
107
extensionNodeChanged += value;
108
foreach (ExtensionNode node in ChildNodes) {
110
extensionNodeChanged (this, new ExtensionNodeEventArgs (ExtensionChange.Add, node));
111
} catch (Exception ex) {
112
AddinManager.ReportError (null, null, ex, false);
117
extensionNodeChanged -= value;
121
public ExtensionNodeList ChildNodes {
126
childrenLoaded = true;
129
if (treeNode.Children.Count == 0) {
130
childNodes = ExtensionNodeList.Empty;
134
catch (Exception ex) {
135
AddinManager.ReportError (null, null, ex, false);
136
childNodes = ExtensionNodeList.Empty;
140
ArrayList list = new ArrayList ();
141
foreach (TreeNode cn in treeNode.Children) {
143
// For each node check if it is visible for the current context.
144
// If something fails while evaluating the condition, just ignore the node.
147
if (cn.ExtensionNode != null && cn.IsEnabled)
148
list.Add (cn.ExtensionNode);
149
} catch (Exception ex) {
150
AddinManager.ReportError (null, null, ex, false);
154
childNodes = new ExtensionNodeList (list);
156
childNodes = ExtensionNodeList.Empty;
162
public object[] GetChildObjects ()
164
return GetChildObjects (typeof(object), true);
167
public object[] GetChildObjects (bool reuseCachedInstance)
169
return GetChildObjects (typeof(object), reuseCachedInstance);
172
public object[] GetChildObjects (Type arrayElementType)
174
return GetChildObjects (arrayElementType, true);
177
public object[] GetChildObjects (Type arrayElementType, bool reuseCachedInstance)
179
ArrayList list = new ArrayList (ChildNodes.Count);
181
for (int n=0; n<ChildNodes.Count; n++) {
182
InstanceExtensionNode node = ChildNodes [n] as InstanceExtensionNode;
184
AddinManager.ReportError ("Error while getting object for node in path '" + Path + "'. Extension node is not a subclass of InstanceExtensionNode.", null, null, false);
189
if (reuseCachedInstance)
190
list.Add (node.GetInstance (arrayElementType));
192
list.Add (node.CreateInstance (arrayElementType));
194
catch (Exception ex) {
195
AddinManager.ReportError ("Error while getting object for node in path '" + Path + "'.", null, ex, false);
198
return (object[]) list.ToArray (arrayElementType);
201
internal protected virtual void Read (NodeElement elem)
203
if (nodeType == null || nodeType.Fields == null)
206
NodeAttribute[] attributes = elem.Attributes;
207
Hashtable fields = (Hashtable) nodeType.Fields.Clone ();
209
foreach (NodeAttribute at in attributes) {
211
ExtensionNodeType.FieldData f = (ExtensionNodeType.FieldData) fields [at.name];
215
fields.Remove (at.name);
219
if (f.Field.FieldType == typeof(string)) {
221
val = Addin.Localizer.GetString (at.value);
225
else if (f.Field.FieldType == typeof(string[])) {
226
string[] ss = at.value.Split (',');
227
if (ss.Length == 0 && ss[0].Length == 0)
228
val = new string [0];
230
for (int n=0; n<ss.Length; n++)
231
ss [n] = ss[n].Trim ();
235
else if (f.Field.FieldType.IsEnum) {
236
val = Enum.Parse (f.Field.FieldType, at.value);
240
val = Convert.ChangeType (at.Value, f.Field.FieldType);
241
} catch (InvalidCastException) {
242
throw new InvalidOperationException ("Property type not supported by [NodeAttribute]: " + f.Field.DeclaringType + "." + f.Field.Name);
246
f.Field.SetValue (this, val);
249
if (fields.Count > 0) {
250
// Check if one of the remaining fields is mandatory
251
foreach (DictionaryEntry e in fields) {
252
ExtensionNodeType.FieldData f = (ExtensionNodeType.FieldData) e.Value;
254
throw new InvalidOperationException ("Required attribute '" + e.Key + "' not found.");
259
internal bool NotifyChildChanged ()
264
ExtensionNodeList oldList = childNodes;
265
childrenLoaded = false;
267
bool changed = false;
269
foreach (ExtensionNode nod in oldList) {
270
if (ChildNodes [nod.Id] == null) {
272
OnChildNodeRemoved (nod);
275
foreach (ExtensionNode nod in ChildNodes) {
276
if (oldList [nod.Id] == null) {
278
OnChildNodeAdded (nod);
282
OnChildrenChanged ();
286
// Called when the add-in that defined this extension node is actually
288
internal protected virtual void OnAddinLoaded ()
292
// Called when the add-in that defined this extension node is being
293
// unloaded from memory.
294
internal protected virtual void OnAddinUnloaded ()
298
// Called when the children list of this node has changed. It may be due to add-ins
299
// being loaded/unloaded, or to conditions being changed.
300
protected virtual void OnChildrenChanged ()
304
protected virtual void OnChildNodeAdded (ExtensionNode node)
306
if (extensionNodeChanged != null)
307
extensionNodeChanged (this, new ExtensionNodeEventArgs (ExtensionChange.Add, node));
310
protected virtual void OnChildNodeRemoved (ExtensionNode node)
312
if (extensionNodeChanged != null)
313
extensionNodeChanged (this, new ExtensionNodeEventArgs (ExtensionChange.Remove, node));