1 // 2 // ExtensionNodeDescription.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.Xml; 32 using System.Collections.Specialized; 33 using Mono.Addins.Serialization; 34 35 namespace Mono.Addins.Description 36 { 37 /// <summary> 38 /// An extension node definition. 39 /// </summary> 40 public class ExtensionNodeDescription: ObjectDescription, NodeElement 41 { 42 ExtensionNodeDescriptionCollection childNodes; 43 string[] attributes; 44 string nodeName; 45 46 /// <summary> 47 /// Initializes a new instance of the <see cref="Mono.Addins.Description.ExtensionNodeDescription"/> class. 48 /// </summary> 49 /// <param name='nodeName'> 50 /// Node name. 51 /// </param> ExtensionNodeDescription(string nodeName)52 public ExtensionNodeDescription (string nodeName) 53 { 54 this.nodeName = nodeName; 55 } 56 ExtensionNodeDescription(XmlElement elem)57 internal ExtensionNodeDescription (XmlElement elem) 58 { 59 Element = elem; 60 nodeName = elem.LocalName; 61 } 62 ExtensionNodeDescription()63 internal ExtensionNodeDescription () 64 { 65 } 66 67 /// <summary> 68 /// Gets the type of the node. 69 /// </summary> 70 /// <returns> 71 /// The node type. 72 /// </returns> 73 /// <remarks> 74 /// This method only works when the add-in description to which the node belongs has been 75 /// loaded from an add-in registry. 76 /// </remarks> GetNodeType()77 public ExtensionNodeType GetNodeType () 78 { 79 if (Parent is Extension) { 80 Extension ext = (Extension) Parent; 81 object ob = ext.GetExtendedObject (); 82 if (ob is ExtensionPoint) { 83 ExtensionPoint ep = (ExtensionPoint) ob; 84 return ep.NodeSet.GetAllowedNodeTypes () [NodeName]; 85 } else if (ob is ExtensionNodeDescription) { 86 ExtensionNodeDescription pn = (ExtensionNodeDescription) ob; 87 ExtensionNodeType pt = ((ExtensionNodeDescription) pn).GetNodeType (); 88 if (pt != null) 89 return pt.GetAllowedNodeTypes () [NodeName]; 90 } 91 } 92 else if (Parent is ExtensionNodeDescription) { 93 ExtensionNodeType pt = ((ExtensionNodeDescription) Parent).GetNodeType (); 94 if (pt != null) 95 return pt.GetAllowedNodeTypes () [NodeName]; 96 } 97 return null; 98 } 99 100 /// <summary> 101 /// Gets the extension path under which this node is registered 102 /// </summary> 103 /// <returns> 104 /// The parent path. 105 /// </returns> 106 /// <remarks> 107 /// For example, if the id of the node is 'ThisNode', and the node is a child of another node with id 'ParentNode', and 108 /// that parent node is defined in an extension with the path '/Core/MainExtension', then the parent path is 'Core/MainExtension/ParentNode'. 109 /// </remarks> GetParentPath()110 public string GetParentPath () 111 { 112 if (Parent is Extension) 113 return ((Extension)Parent).Path; 114 else if (Parent is ExtensionNodeDescription) { 115 ExtensionNodeDescription pn = (ExtensionNodeDescription) Parent; 116 return pn.GetParentPath () + "/" + pn.Id; 117 } 118 else 119 return string.Empty; 120 } 121 Verify(string location, StringCollection errors)122 internal override void Verify (string location, StringCollection errors) 123 { 124 if (nodeName == null || nodeName.Length == 0) 125 errors.Add (location + "Node: NodeName can't be empty."); 126 ChildNodes.Verify (location + NodeName + "/", errors); 127 } 128 129 /// <summary> 130 /// Gets or sets the name of the node. 131 /// </summary> 132 /// <value> 133 /// The name of the node. 134 /// </value> 135 public string NodeName { 136 get { return nodeName; } 137 internal set { 138 if (Element != null) 139 throw new InvalidOperationException ("Can't change node name of xml element"); 140 nodeName = value; 141 } 142 } 143 144 /// <summary> 145 /// Gets or sets the identifier of the node. 146 /// </summary> 147 /// <value> 148 /// The identifier. 149 /// </value> 150 public string Id { 151 get { return GetAttribute ("id"); } 152 set { SetAttribute ("id", value); } 153 } 154 155 /// <summary> 156 /// Gets or sets the identifier of the node after which this node has to be inserted 157 /// </summary> 158 /// <value> 159 /// The identifier of the reference node 160 /// </value> 161 public string InsertAfter { 162 get { return GetAttribute ("insertafter"); } 163 set { 164 if (value == null || value.Length == 0) 165 RemoveAttribute ("insertafter"); 166 else 167 SetAttribute ("insertafter", value); 168 } 169 } 170 171 /// <summary> 172 /// Gets or sets the identifier of the node before which this node has to be inserted 173 /// </summary> 174 /// <value> 175 /// The identifier of the reference node 176 /// </value> 177 public string InsertBefore { 178 get { return GetAttribute ("insertbefore"); } 179 set { 180 if (value == null || value.Length == 0) 181 RemoveAttribute ("insertbefore"); 182 else 183 SetAttribute ("insertbefore", value); 184 } 185 } 186 187 /// <summary> 188 /// Gets a value indicating whether this node is a condition. 189 /// </summary> 190 /// <value> 191 /// <c>true</c> if this node is a condition; otherwise, <c>false</c>. 192 /// </value> 193 public bool IsCondition { 194 get { return nodeName == "Condition" || nodeName == "ComplexCondition"; } 195 } 196 SaveXml(XmlElement parent)197 internal override void SaveXml (XmlElement parent) 198 { 199 if (Element == null) { 200 Element = parent.OwnerDocument.CreateElement (nodeName); 201 parent.AppendChild (Element); 202 if (attributes != null) { 203 for (int n=0; n<attributes.Length; n+=2) 204 Element.SetAttribute (attributes[n], attributes[n+1]); 205 } 206 ChildNodes.SaveXml (Element); 207 } 208 } 209 210 /// <summary> 211 /// Gets the value of an attribute. 212 /// </summary> 213 /// <returns> 214 /// The value of the attribute, or an empty string if the attribute is not defined. 215 /// </returns> 216 /// <param name='key'> 217 /// Name of the attribute. 218 /// </param> GetAttribute(string key)219 public string GetAttribute (string key) 220 { 221 if (Element != null) 222 return Element.GetAttribute (key); 223 224 if (attributes == null) 225 return string.Empty; 226 for (int n=0; n<attributes.Length; n+=2) { 227 if (attributes [n] == key) 228 return attributes [n+1]; 229 } 230 return string.Empty; 231 } 232 233 /// <summary> 234 /// Sets the value of an attribute. 235 /// </summary> 236 /// <param name='key'> 237 /// Name of the attribute 238 /// </param> 239 /// <param name='value'> 240 /// The value. 241 /// </param> SetAttribute(string key, string value)242 public void SetAttribute (string key, string value) 243 { 244 if (Element != null) { 245 Element.SetAttribute (key, value); 246 return; 247 } 248 249 if (value == null) 250 value = string.Empty; 251 252 if (attributes == null) { 253 attributes = new string [2]; 254 attributes [0] = key; 255 attributes [1] = value; 256 return; 257 } 258 259 for (int n=0; n<attributes.Length; n+=2) { 260 if (attributes [n] == key) { 261 attributes [n+1] = value; 262 return; 263 } 264 } 265 string[] newList = new string [attributes.Length + 2]; 266 attributes.CopyTo (newList, 0); 267 attributes = newList; 268 attributes [attributes.Length - 2] = key; 269 attributes [attributes.Length - 1] = value; 270 } 271 272 /// <summary> 273 /// Removes an attribute. 274 /// </summary> 275 /// <param name='name'> 276 /// Name of the attribute to remove. 277 /// </param> RemoveAttribute(string name)278 public void RemoveAttribute (string name) 279 { 280 if (Element != null) { 281 Element.RemoveAttribute (name); 282 return; 283 } 284 285 if (attributes == null) 286 return; 287 288 for (int n=0; n<attributes.Length; n+=2) { 289 if (attributes [n] == name) { 290 string[] newar = new string [attributes.Length - 2]; 291 Array.Copy (attributes, 0, newar, 0, n); 292 Array.Copy (attributes, n+2, newar, n, attributes.Length - n - 2); 293 attributes = newar; 294 break; 295 } 296 } 297 } 298 299 /// <summary> 300 /// Gets the attributes of the node. 301 /// </summary> 302 /// <value> 303 /// The attributes. 304 /// </value> 305 public NodeAttribute[] Attributes { 306 get { 307 if (Element != null) 308 SaveXmlAttributes (); 309 if (attributes == null) 310 return new NodeAttribute [0]; 311 NodeAttribute[] ats = new NodeAttribute [attributes.Length / 2]; 312 for (int n=0; n<ats.Length; n++) { 313 NodeAttribute at = new NodeAttribute (); 314 at.name = attributes [n*2]; 315 at.value = attributes [n*2 + 1]; 316 ats [n] = at; 317 } 318 return ats; 319 } 320 } 321 322 /// <summary> 323 /// Gets the child nodes. 324 /// </summary> 325 /// <value> 326 /// The child nodes. 327 /// </value> 328 public ExtensionNodeDescriptionCollection ChildNodes { 329 get { 330 if (childNodes == null) { 331 childNodes = new ExtensionNodeDescriptionCollection (this); 332 if (Element != null) { 333 foreach (XmlNode nod in Element.ChildNodes) { 334 if (nod is XmlElement) 335 childNodes.Add (new ExtensionNodeDescription ((XmlElement)nod)); 336 } 337 } 338 } 339 return childNodes; 340 } 341 } 342 343 NodeElementCollection NodeElement.ChildNodes { 344 get { return ChildNodes; } 345 } 346 SaveXmlAttributes()347 void SaveXmlAttributes () 348 { 349 attributes = new string [Element.Attributes.Count * 2]; 350 for (int n=0; n<attributes.Length; n+=2) { 351 XmlAttribute at = Element.Attributes [n/2]; 352 attributes [n] = at.LocalName; 353 attributes [n+1] = at.Value; 354 } 355 } 356 Write(BinaryXmlWriter writer)357 internal override void Write (BinaryXmlWriter writer) 358 { 359 if (Element != null) 360 SaveXmlAttributes (); 361 362 writer.WriteValue ("nodeName", nodeName); 363 writer.WriteValue ("attributes", attributes); 364 writer.WriteValue ("ChildNodes", ChildNodes); 365 } 366 Read(BinaryXmlReader reader)367 internal override void Read (BinaryXmlReader reader) 368 { 369 nodeName = reader.ReadStringValue ("nodeName"); 370 attributes = (string[]) reader.ReadValue ("attributes"); 371 childNodes = (ExtensionNodeDescriptionCollection) reader.ReadValue ("ChildNodes", new ExtensionNodeDescriptionCollection (this)); 372 } 373 } 374 } 375