//
// System.Configuration.ConfigurationElementCollection.cs
//
// Authors:
// Tim Coleman (tim@timcoleman.com)
//
// Copyright (C) Tim Coleman, 2004
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
#if NET_2_0
using System.Collections;
using System.Diagnostics;
using System.Xml;
namespace System.Configuration{
[DebuggerDisplayAttribute ("Count = {Count}")]
public abstract partial class ConfigurationElementCollection : ConfigurationElement, ICollection, IEnumerable
{
ArrayList list = new ArrayList ();
ArrayList removed;
ArrayList inherited;
bool emitClear;
bool modified;
IComparer comparer;
int inheritedLimitIndex;
string addElementName = "add";
string clearElementName = "clear";
string removeElementName = "remove";
#region Constructors
protected ConfigurationElementCollection ()
{
}
protected ConfigurationElementCollection (IComparer comparer)
{
this.comparer = comparer;
}
internal override void InitFromProperty (PropertyInformation propertyInfo)
{
ConfigurationCollectionAttribute colat = propertyInfo.Property.CollectionAttribute;
if (colat == null)
colat = Attribute.GetCustomAttribute (propertyInfo.Type, typeof (ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
if (colat != null) {
addElementName = colat.AddItemName;
clearElementName = colat.ClearItemsName;
removeElementName = colat.RemoveItemName;
}
base.InitFromProperty (propertyInfo);
}
#endregion // Constructors
#region Properties
public virtual ConfigurationElementCollectionType CollectionType {
get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
}
bool IsBasic {
get {
return CollectionType == ConfigurationElementCollectionType.BasicMap ||
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
}
}
bool IsAlternate {
get {
return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate ||
CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
}
}
public int Count {
get { return list.Count; }
}
protected virtual string ElementName {
get { return string.Empty; }
}
public bool EmitClear {
get { return emitClear; }
set { emitClear = value; }
}
public bool IsSynchronized {
get { return false; }
}
public object SyncRoot {
get { return this; }
}
protected virtual bool ThrowOnDuplicate {
get {
if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate)
return false;
return true;
}
}
protected internal string AddElementName {
get { return addElementName; }
set { addElementName = value; }
}
protected internal string ClearElementName {
get { return clearElementName; }
set { clearElementName = value; }
}
protected internal string RemoveElementName {
get { return removeElementName; }
set { removeElementName = value; }
}
#endregion // Properties
#region Methods
protected virtual void BaseAdd (ConfigurationElement element)
{
BaseAdd (element, ThrowOnDuplicate);
}
protected void BaseAdd (ConfigurationElement element, bool throwIfExists)
{
if (IsReadOnly ())
throw new ConfigurationErrorsException ("Collection is read only.");
if (IsAlternate) {
list.Insert (inheritedLimitIndex, element);
inheritedLimitIndex++;
}
else {
int old_index = IndexOfKey (GetElementKey (element));
if (old_index >= 0) {
if (element.Equals (list [old_index]))
return;
if (throwIfExists)
throw new ConfigurationException ("Duplicate element in collection");
list.RemoveAt (old_index);
}
list.Add (element);
}
modified = true;
}
protected virtual void BaseAdd (int index, ConfigurationElement element)
{
if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
throw new ConfigurationException ("Duplicate element in collection");
if (IsReadOnly ())
throw new ConfigurationErrorsException ("Collection is read only.");
if (IsAlternate && (index > inheritedLimitIndex))
throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
if (!IsAlternate && (index <= inheritedLimitIndex))
throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
list.Insert (index, element);
modified = true;
}
protected internal void BaseClear ()
{
if (IsReadOnly ())
throw new ConfigurationErrorsException ("Collection is read only.");
list.Clear ();
modified = true;
}
protected internal ConfigurationElement BaseGet (int index)
{
return (ConfigurationElement) list [index];
}
protected internal ConfigurationElement BaseGet (object key)
{
int index = IndexOfKey (key);
if (index != -1) return (ConfigurationElement) list [index];
else return null;
}
protected internal object[] BaseGetAllKeys ()
{
object[] keys = new object [list.Count];
for (int n=0; n<list.Count; n++)
keys [n] = BaseGetKey (n);
return keys;
}
protected internal object BaseGetKey (int index)
{
if (index < 0 || index >= list.Count)
throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
return GetElementKey ((ConfigurationElement) list[index]).ToString ();
}
protected int BaseIndexOf (ConfigurationElement element)
{
return list.IndexOf (element);
}
int IndexOfKey (object key)
{
for (int n=0; n<list.Count; n++) {
if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
return n;
}
return -1;
}
protected internal bool BaseIsRemoved (object key)
{
if (removed == null)
return false;
foreach (ConfigurationElement elem in removed) {
if (CompareKeys (GetElementKey (elem), key))
return true;
}
return false;
}
protected internal void BaseRemove (object key)
{
if (IsReadOnly ())
throw new ConfigurationErrorsException ("Collection is read only.");
int index = IndexOfKey (key);
if (index != -1) {
BaseRemoveAt (index);
modified = true;
}
}
protected internal void BaseRemoveAt (int index)
{
if (IsReadOnly ())
throw new ConfigurationErrorsException ("Collection is read only.");
ConfigurationElement elem = (ConfigurationElement) list [index];
if (!IsElementRemovable (elem))
throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
if (inherited != null && inherited.Contains (elem))
throw new ConfigurationErrorsException ("Inherited items can't be removed.");
list.RemoveAt (index);
modified = true;
}
bool CompareKeys (object key1, object key2)
{
if (comparer != null)
return comparer.Compare (key1, key2) == 0;
else
return object.Equals (key1, key2);
}
public void CopyTo (ConfigurationElement[] array, int index)
{
list.CopyTo (array, index);
}
protected abstract ConfigurationElement CreateNewElement ();
protected virtual ConfigurationElement CreateNewElement (string elementName)
{
return CreateNewElement ();
}
ConfigurationElement CreateNewElementInternal (string elementName)
{
ConfigurationElement elem;
if (elementName == null)
elem = CreateNewElement ();
else
elem = CreateNewElement (elementName);
elem.Init ();
return elem;
}
public override bool Equals (object compareTo)
{
ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
if (other == null) return false;
if (GetType() != other.GetType()) return false;
if (Count != other.Count) return false;
for (int n=0; n<Count; n++) {
if (!BaseGet (n).Equals (other.BaseGet (n)))
return false;
}
return true;
}
protected abstract object GetElementKey (ConfigurationElement element);
public override int GetHashCode ()
{
int code = 0;
for (int n=0; n<Count; n++)
code += BaseGet (n).GetHashCode ();
return code;
}
void ICollection.CopyTo (Array arr, int index)
{
list.CopyTo (arr, index);
}
public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
protected virtual bool IsElementName (string elementName)
{
return false;
}
protected virtual bool IsElementRemovable (ConfigurationElement element)
{
return !IsReadOnly ();
}
protected internal override bool IsModified ()
{
return modified;
}
[MonoTODO]
public override bool IsReadOnly ()
{
return base.IsReadOnly ();
}
internal override bool HasValues ()
{
return list.Count > 0;
}
protected internal override void Reset (ConfigurationElement parentElement)
{
bool basic = IsBasic;
ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
for (int n=0; n<parent.Count; n++)
{
ConfigurationElement parentItem = parent.BaseGet (n);
ConfigurationElement item = CreateNewElementInternal (null);
item.Reset (parentItem);
BaseAdd (item);
if (basic) {
if (inherited == null)
inherited = new ArrayList ();
inherited.Add (item);
}
}
if (IsAlternate)
inheritedLimitIndex = 0;
else
inheritedLimitIndex = Count - 1;
modified = false;
}
protected internal override void ResetModified ()
{
modified = false;
}
[MonoTODO]
protected internal override void SetReadOnly ()
{
base.SetReadOnly ();
}
protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
{
if (serializeCollectionKey) {
return base.SerializeElement (writer, serializeCollectionKey);
}
bool wroteData = false;
if (IsBasic)
{
for (int n=0; n<list.Count; n++) {
ConfigurationElement elem = (ConfigurationElement) list [n];
if (ElementName != string.Empty)
wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
else
wroteData = elem.SerializeElement (writer, false) || wroteData;
}
}
else
{
if (emitClear) {
writer.WriteElementString (clearElementName, "");
wroteData = true;
}
if (removed != null) {
for (int n=0; n<removed.Count; n++) {
writer.WriteStartElement (removeElementName);
((ConfigurationElement)removed[n]).SerializeElement (writer, true);
writer.WriteEndElement ();
}
wroteData = wroteData || removed.Count > 0;
}
for (int n=0; n<list.Count; n++) {
ConfigurationElement elem = (ConfigurationElement) list [n];
elem.SerializeToXmlElement (writer, addElementName);
}
wroteData = wroteData || list.Count > 0;
}
return wroteData;
}
protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
{
if (IsBasic)
{
ConfigurationElement elem = null;
if (elementName == ElementName)
elem = CreateNewElementInternal (null);
if (IsElementName (elementName))
elem = CreateNewElementInternal (elementName);
if (elem != null) {
elem.DeserializeElement (reader, false);
BaseAdd (elem);
modified = false;
return true;
}
}
else {
if (elementName == clearElementName) {
reader.MoveToContent ();
if (reader.MoveToNextAttribute ())
throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
reader.MoveToElement ();
reader.Skip ();
BaseClear ();
emitClear = true;
modified = false;
return true;
}
else if (elementName == removeElementName) {
ConfigurationElement elem = CreateNewElementInternal (null);
ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
removeElem.DeserializeElement (reader, true);
BaseRemove (removeElem.KeyValue);
modified = false;
return true;
}
else if (elementName == addElementName) {
ConfigurationElement elem = CreateNewElementInternal (null);
elem.DeserializeElement (reader, false);
BaseAdd (elem);
modified = false;
return true;
}
}
return false;
}
protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
{
ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
for (int n=0; n<source.Count; n++) {
ConfigurationElement sitem = source.BaseGet (n);
object key = source.GetElementKey (sitem);
ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
ConfigurationElement nitem = CreateNewElementInternal (null);
nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
if (nitem.HasValues ())
BaseAdd (nitem);
}
else {
ConfigurationElement nitem = CreateNewElementInternal (null);
nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
BaseAdd (nitem);
}
}
if (updateMode == ConfigurationSaveMode.Full)
EmitClear = true;
else if (parent != null) {
for (int n=0; n<parent.Count; n++) {
ConfigurationElement pitem = parent.BaseGet (n);
object key = parent.GetElementKey (pitem);
if (source.IndexOfKey (key) == -1) {
if (removed == null) removed = new ArrayList ();
removed.Add (pitem);
}
}
}
}
#endregion // Methods
}
}
#endif
|