using System; using System.Collections.Generic; using JD.Collections.Extensions; using JD.Collections.Interfaces; using JD.Kernel.Structs; using JD.TeaBoxAddinSystem.Addins.Description; using JD.TeaBoxAddinSystem.Addins.Description.Conditions; using JD.TeaBoxAddinSystem.Addins.Internal; namespace JD.TeaBoxAddinSystem.Addins { /// /// Extension Nodes are the objects that are created and placed in the extension tree. /// public class ExtensionNode : Node { #region Inner Types private class ExtensionNodeCollection : System.Collections.ObjectModel.ReadOnlyCollection, IKeyedList { #region Constructor internal ExtensionNodeCollection(IList list) : base(list) { } #endregion #region Properties public ExtensionNode this[string key] { get { foreach (ExtensionNode node in this) { if (node.Id == key) { return node; } } return null; } } #endregion #region Methods public bool ContainsKey(string key) { return (this[key] != null); } public bool Remove(string key) { throw new NotSupportedException(); } public bool TryGetValue(string key, out ExtensionNode value) { value = this[key]; return value != null; } #endregion } #endregion #region Variables private object m_cachedInstance; // Set through Initialize private TreeNode m_node; // Lazy-constructed private List m_childNodes; private object m_lock = new object(); #endregion #region Properties /// /// Gets the file location of the extension node. /// /// public override sealed FileLocation FileLocation { get { if (m_node != null) { return m_node.ExtensionNodeDescription.FileLocation.GetValueOrDefault(); } return FileLocation.Empty; } } /// /// Type of this extension node. /// public new ExtensionType Type { get { return (ExtensionType)base.Type; } } /// /// Id of the extension node. /// public string Id { get { return m_node.Id; } } /// /// Gets whether the of this was defined by the user or automatically generated. /// public bool HasIdDefined { get { return m_node.HasIdDefined; } } /// /// Full path of the extension node. /// public string FullPath { get { return m_node.FullPath; } } /// /// Child nodes of this extension node. /// public IKeyedList ChildNodes { get { if (m_childNodes == null) { lock (m_lock) { if (m_childNodes == null) { List nodes = new List(m_node.ChildNodes.Count); foreach (TreeNode childNode in m_node.ChildNodes) { ExtensionNode childExtensionNode = childNode.ExtensionNode; if (childExtensionNode != null) { nodes.Add(childExtensionNode); } } m_childNodes = nodes; } } } System.Diagnostics.Debug.Assert(m_childNodes != null); return new ExtensionNodeCollection(m_childNodes); } } /// /// Extension Object of this node. /// /// /// This method is only valid on s /// /// The node is not a . public virtual object ExtensionObject { get { if (m_cachedInstance == null) { m_cachedInstance = CreateExtensionObject(); } return m_cachedInstance; } } #endregion #region Methods /// /// Creates an extension object for this node. /// /// /// This method is only valid on certain extension node types like . /// /// /// This extension node doesn't support extension objects. public virtual object CreateExtensionObject() { throw new InvalidOperationException("ExtensionObjects are only available on TypeExtensionNodes"); } /// /// Gets a collection of extension objects contained in this extension node. /// /// /// All objects created by child nodes MUST be of type . /// /// /// public IList GetExtensionObjects() { return ChildNodes.Project(node => (T)node.ExtensionObject); } internal T GetExtensionObject() { return (T)ExtensionObject; } /// /// Called by a when its collection of child nodes is modified. /// internal void NotifyChildNodesChanged(ExtensionNodeChangedEventArgs e) { // This will trigger a recreation of the nodes on demand. m_childNodes = null; OnChanged(e); } internal bool Initialize(TreeNode node, Module module, ExtensionNodeDescription description, ExtensionType type) { System.Diagnostics.Debug.Assert(node != null); m_node = node; if (!base.Initialize(module, description, type)) { return false; } // Validate conditional targets if (description != null) // Description can be null in case of extension point's fake extension nodes. { foreach (ConditionInfo conditionInfo in description.Conditions) { if (!string.IsNullOrEmpty(conditionInfo.Target) && !type.ConditionAttributes.Contains(conditionInfo.Target)) { description.LogWarning("Cannot apply condition {0} on target {1} of node {2} because it is not supported on extension nodes of type {3}", conditionInfo.Condition, conditionInfo.Target, description.DisplayId, type.Name); } } } return true; } #endregion #region Events /// /// Triggered when this extension node changes. /// public event EventHandler Changed { add { AddinManager.SessionService.AddExtensionChangedHandler(FullPath, value); } remove { AddinManager.SessionService.RemoveExtensionChangedHandler(FullPath, value); } } /// /// Triggers a event. /// /// Event Args. protected virtual void OnChanged(ExtensionNodeChangedEventArgs e) { AddinManager.SessionService.ChangedHandlerManager.OnChanged(e); } #endregion } }