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 Mono.Addins.Serialization;
34
using System.Collections.Specialized;
36
namespace Mono.Addins.Description
39
/// An extension node set definition.
42
/// Node sets allow grouping a set of extension node declarations and give an identifier to that group
43
/// (the node set). Once a node set is declared, it can be referenced from several extension points
44
/// which use the same extension node structure. Extension node sets also allow declaring recursive
45
/// extension nodes, that is, extension nodes with a tree structure.
47
public class ExtensionNodeSet: ObjectDescription
50
ExtensionNodeTypeCollection nodeTypes;
51
NodeSetIdCollection nodeSets;
52
bool missingNodeSetId;
53
ExtensionNodeTypeCollection cachedAllowedTypes;
55
internal string SourceAddinId { get; set; }
57
internal ExtensionNodeSet (XmlElement element)
60
id = element.GetAttribute (IdAttribute);
64
/// Copies data from another node set
66
/// <param name='nset'>
67
/// Node set from which to copy
69
public void CopyFrom (ExtensionNodeSet nset)
73
foreach (ExtensionNodeType nt in nset.NodeTypes) {
74
ExtensionNodeType cnt = new ExtensionNodeType ();
79
foreach (string ns in nset.NodeSets)
81
missingNodeSetId = nset.missingNodeSetId;
84
internal override void Verify (string location, StringCollection errors)
87
errors.Add (location + "Missing id attribute in extension set reference");
89
NodeTypes.Verify (location + "ExtensionNodeSet (" + Id + ")/", errors);
92
internal override void SaveXml (XmlElement parent)
94
SaveXml (parent, "ExtensionNodeSet");
97
internal virtual void SaveXml (XmlElement parent, string nodeName)
99
if (Element == null) {
100
Element = parent.OwnerDocument.CreateElement (nodeName);
101
parent.AppendChild (Element);
104
Element.SetAttribute (IdAttribute, Id);
105
if (nodeTypes != null)
106
nodeTypes.SaveXml (Element);
107
if (nodeSets != null) {
108
foreach (string s in nodeSets) {
109
if (Element.SelectSingleNode ("ExtensionNodeSet[@id='" + s + "']") == null) {
110
XmlElement e = Element.OwnerDocument.CreateElement ("ExtensionNodeSet");
111
e.SetAttribute ("id", s);
112
Element.AppendChild (e);
115
ArrayList list = new ArrayList ();
116
foreach (XmlElement e in Element.SelectNodes ("ExtensionNodeSet")) {
117
if (!nodeSets.Contains (e.GetAttribute ("id")))
120
foreach (XmlElement e in list)
121
Element.RemoveChild (e);
126
/// Initializes a new instance of the <see cref="Mono.Addins.Description.ExtensionNodeSet"/> class.
128
public ExtensionNodeSet ()
133
/// Gets or sets the identifier of the node set.
139
get { return id != null ? id : string.Empty; }
143
internal virtual string IdAttribute {
148
/// Gets the node types allowed in this node set.
153
public ExtensionNodeTypeCollection NodeTypes {
155
if (nodeTypes == null) {
159
nodeTypes = new ExtensionNodeTypeCollection (this);
166
/// Gets a list of other node sets included in this node set.
171
public NodeSetIdCollection NodeSets {
173
if (nodeSets == null) {
177
nodeSets = new NodeSetIdCollection ();
184
/// Gets all the allowed node types.
187
/// The allowed node types.
190
/// Gets all allowed node types, including those defined in included node sets.
191
/// This method only works for descriptions loaded from a registry.
193
public ExtensionNodeTypeCollection GetAllowedNodeTypes ()
195
if (cachedAllowedTypes == null) {
196
cachedAllowedTypes = new ExtensionNodeTypeCollection ();
197
GetAllowedNodeTypes (new Hashtable (), cachedAllowedTypes);
199
return cachedAllowedTypes;
202
void GetAllowedNodeTypes (Hashtable visitedSets, ExtensionNodeTypeCollection col)
205
if (visitedSets.Contains (Id))
207
visitedSets [Id] = Id;
210
// Gets all allowed node types, including those defined in node sets
211
// It only works for descriptions generated from a registry
213
foreach (ExtensionNodeType nt in NodeTypes)
216
AddinDescription desc = ParentAddinDescription;
217
if (desc == null || desc.OwnerDatabase == null)
220
foreach (string[] ns in NodeSets.InternalList) {
221
string startAddin = ns [1];
222
if (startAddin == null || startAddin.Length == 0)
223
startAddin = desc.AddinId;
224
ExtensionNodeSet nset = desc.OwnerDatabase.FindNodeSet (ParentAddinDescription.Domain, startAddin, ns[0]);
226
nset.GetAllowedNodeTypes (visitedSets, col);
230
internal void Clear ()
237
internal void SetExtensionsAddinId (string addinId)
239
foreach (ExtensionNodeType nt in NodeTypes) {
240
nt.AddinId = addinId;
241
nt.SetExtensionsAddinId (addinId);
243
NodeSets.SetExtensionsAddinId (addinId);
246
internal void MergeWith (string thisAddinId, ExtensionNodeSet other)
248
foreach (ExtensionNodeType nt in other.NodeTypes) {
249
if (nt.AddinId != thisAddinId && !NodeTypes.Contains (nt))
252
NodeSets.MergeWith (thisAddinId, other.NodeSets);
255
internal void UnmergeExternalData (string thisAddinId, Hashtable addinsToUnmerge)
257
// Removes extension types and extension sets coming from other add-ins.
259
ArrayList todelete = new ArrayList ();
260
foreach (ExtensionNodeType nt in NodeTypes) {
261
if (nt.AddinId != thisAddinId && (addinsToUnmerge == null || addinsToUnmerge.Contains (nt.AddinId)))
264
foreach (ExtensionNodeType nt in todelete)
265
NodeTypes.Remove (nt);
267
NodeSets.UnmergeExternalData (thisAddinId, addinsToUnmerge);
270
void InitCollections ()
272
nodeTypes = new ExtensionNodeTypeCollection (this);
273
nodeSets = new NodeSetIdCollection ();
275
foreach (XmlNode n in Element.ChildNodes) {
276
XmlElement nt = n as XmlElement;
279
if (nt.LocalName == "ExtensionNode") {
280
ExtensionNodeType etype = new ExtensionNodeType (nt);
281
nodeTypes.Add (etype);
283
else if (nt.LocalName == "ExtensionNodeSet") {
284
string id = nt.GetAttribute ("id");
288
missingNodeSetId = true;
293
internal override void Write (BinaryXmlWriter writer)
295
writer.WriteValue ("Id", id);
296
writer.WriteValue ("NodeTypes", NodeTypes);
297
writer.WriteValue ("NodeSets", NodeSets.InternalList);
300
internal override void Read (BinaryXmlReader reader)
302
id = reader.ReadStringValue ("Id");
303
nodeTypes = (ExtensionNodeTypeCollection) reader.ReadValue ("NodeTypes", new ExtensionNodeTypeCollection (this));
304
reader.ReadValue ("NodeSets", NodeSets.InternalList);
309
/// A collection of node set identifiers
311
public class NodeSetIdCollection: IEnumerable
313
// A list of string[2]. Item 0 is the node set id, item 1 is the addin that defines it.
315
ArrayList list = new ArrayList ();
318
/// Gets the node set identifier at the specified index.
323
public string this [int n] {
324
get { return ((string[])list [n])[0]; }
328
/// Gets the item count.
334
get { return list.Count; }
338
/// Gets the collection enumerator.
343
public IEnumerator GetEnumerator ()
345
ArrayList ll = new ArrayList (list.Count);
346
foreach (string[] ns in list)
348
return ll.GetEnumerator ();
352
/// Add the specified node set identifier.
354
/// <param name='nodeSetId'>
355
/// Node set identifier.
357
public void Add (string nodeSetId)
359
if (!Contains (nodeSetId))
360
list.Add (new string [] { nodeSetId, null });
364
/// Remove a node set identifier
366
/// <param name='nodeSetId'>
367
/// Node set identifier.
369
public void Remove (string nodeSetId)
371
int i = IndexOf (nodeSetId);
377
/// Clears the collection
385
/// Checks if the specified identifier is present in the collection
387
/// <param name='nodeSetId'>
388
/// <c>true</c> if the node set identifier is present.
390
public bool Contains (string nodeSetId)
392
return IndexOf (nodeSetId) != -1;
396
/// Returns the index of the specified node set identifier
401
/// <param name='nodeSetId'>
402
/// A node set identifier.
404
public int IndexOf (string nodeSetId)
406
for (int n=0; n<list.Count; n++)
407
if (((string[])list [n])[0] == nodeSetId)
412
internal void SetExtensionsAddinId (string id)
414
foreach (string[] ns in list)
418
internal ArrayList InternalList {
420
set { list = value; }
423
internal void MergeWith (string thisAddinId, NodeSetIdCollection other)
425
foreach (string[] ns in other.list) {
426
if (ns [1] != thisAddinId && !list.Contains (ns))
431
internal void UnmergeExternalData (string thisAddinId, Hashtable addinsToUnmerge)
433
ArrayList newList = new ArrayList ();
434
foreach (string[] ns in list) {
435
if (ns[1] == thisAddinId || (addinsToUnmerge != null && !addinsToUnmerge.Contains (ns[1])))