120 lines
3.8 KiB
C#
120 lines
3.8 KiB
C#
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace ICSharpCode.AvalonEdit.Xml
|
|
{
|
|
/// <summary>
|
|
/// Specailized attribute collection with attribute name caching
|
|
/// </summary>
|
|
public class AXmlAttributeCollection: FilteredCollection<AXmlAttribute, AXmlObjectCollection<AXmlObject>>
|
|
{
|
|
/// <summary> Empty unbound collection </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes",
|
|
Justification = "InsertItem prevents modifying the Empty collection")]
|
|
public static readonly AXmlAttributeCollection Empty = new AXmlAttributeCollection();
|
|
|
|
/// <summary> Create unbound collection </summary>
|
|
protected AXmlAttributeCollection() {}
|
|
|
|
/// <summary> Wrap the given collection. Non-attributes are filtered </summary>
|
|
public AXmlAttributeCollection(AXmlObjectCollection<AXmlObject> source): base(source) {}
|
|
|
|
/// <summary> Wrap the given collection. Non-attributes are filtered. Items not matching the condition are filtered. </summary>
|
|
public AXmlAttributeCollection(AXmlObjectCollection<AXmlObject> source, Predicate<object> condition): base(source, condition) {}
|
|
|
|
Dictionary<string, List<AXmlAttribute>> hashtable = new Dictionary<string, List<AXmlAttribute>>();
|
|
|
|
void AddToHashtable(AXmlAttribute attr)
|
|
{
|
|
string localName = attr.LocalName;
|
|
if (!hashtable.ContainsKey(localName)) {
|
|
hashtable[localName] = new List<AXmlAttribute>(1);
|
|
}
|
|
hashtable[localName].Add(attr);
|
|
}
|
|
|
|
void RemoveFromHashtable(AXmlAttribute attr)
|
|
{
|
|
string localName = attr.LocalName;
|
|
hashtable[localName].Remove(attr);
|
|
}
|
|
|
|
static List<AXmlAttribute> NoAttributes = new List<AXmlAttribute>();
|
|
|
|
/// <summary>
|
|
/// Get all attributes with given local name.
|
|
/// Hash table is used for lookup so this is cheap.
|
|
/// </summary>
|
|
public IEnumerable<AXmlAttribute> GetByLocalName(string localName)
|
|
{
|
|
if (hashtable.ContainsKey(localName)) {
|
|
return hashtable[localName];
|
|
} else {
|
|
return NoAttributes;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void ClearItems()
|
|
{
|
|
foreach(AXmlAttribute item in this) {
|
|
RemoveFromHashtable(item);
|
|
item.Changing -= item_Changing;
|
|
item.Changed -= item_Changed;
|
|
}
|
|
base.ClearItems();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void InsertItem(int index, AXmlAttribute item)
|
|
{
|
|
// prevent insertions into the static 'Empty' instance
|
|
if (this == Empty)
|
|
throw new NotSupportedException("Cannot insert into AXmlAttributeCollection.Empty");
|
|
|
|
AddToHashtable(item);
|
|
item.Changing += item_Changing;
|
|
item.Changed += item_Changed;
|
|
base.InsertItem(index, item);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void RemoveItem(int index)
|
|
{
|
|
RemoveFromHashtable(this[index]);
|
|
this[index].Changing -= item_Changing;
|
|
this[index].Changed -= item_Changed;
|
|
base.RemoveItem(index);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void SetItem(int index, AXmlAttribute item)
|
|
{
|
|
RemoveFromHashtable(this[index]);
|
|
this[index].Changing -= item_Changing;
|
|
this[index].Changed -= item_Changed;
|
|
|
|
AddToHashtable(item);
|
|
item.Changing += item_Changing;
|
|
item.Changed += item_Changed;
|
|
base.SetItem(index, item);
|
|
}
|
|
|
|
// Every item in the collection should be registered to these handlers
|
|
// so that we can handle renames
|
|
|
|
void item_Changing(object sender, AXmlObjectEventArgs e)
|
|
{
|
|
RemoveFromHashtable((AXmlAttribute)e.Object);
|
|
}
|
|
|
|
void item_Changed(object sender, AXmlObjectEventArgs e)
|
|
{
|
|
AddToHashtable((AXmlAttribute)e.Object);
|
|
}
|
|
}
|
|
}
|