using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using Netron.NetronLight; namespace Netron.Diagramming.Core { /// /// CollectionBase is a base class that can be used to more easily implement the /// generic ICollection<T> and non-generic ICollection interfaces. /// /// /// To use CollectionBase as a base class, the derived class must override /// the Count, GetEnumerator, Add, Clear, and Remove methods. /// ICollection<T>.Contains need not be implemented by the /// derived class, but it should be strongly considered, because the CollectionBase implementation /// may not be very efficient. /// /// The item type of the collection. [DebuggerDisplay("{DebuggerDisplayString()}")] public partial class CollectionBase : ICollection, ICollection, IList, ICollectionBase, IShowable { #region Events /// /// Occurs when an item is added to the collection. /// public event EventHandler> OnItemAdded; /// /// Occurs when an item is removed from the collection. /// public event EventHandler> OnItemRemoved; /// /// Occurs when the collection is cleared. /// public event EventHandler OnClear; #endregion #region Fields /// /// the internal generic list on which this collection is based /// protected List innerList; /// /// whether this collection is readonly /// bool mReadOnly = false; #endregion #region Properties /// /// Indicates whether the collection is read-only. /// bool ICollection.IsReadOnly { get { return mReadOnly; } } /// /// Gets a value indicating whether this instance is empty. /// /// true if this instance is empty; otherwise, false. public virtual bool IsEmpty { get { return this.innerList.Count == 0; } } #endregion #region Constructor /// /// Creates a new CollectionBase. /// public CollectionBase() { innerList = new List(); } /// /// Initializes a new instance of the class. /// /// The base collection. public CollectionBase(ICollectionBase baseCollection) : this() { innerList.AddRange(baseCollection); } /// /// Initializes a new instance of the class. /// /// The base collection. /// if set to true [read only]. public CollectionBase(ICollectionBase baseCollection, bool readOnly) : this() { mReadOnly = readOnly; //innerList = new System.Collections.ObjectModel.ReadOnlyCollection(baseCollection); innerList.AddRange(baseCollection); } #endregion /// /// Shows the string representation of the collection. The string representation contains /// a list of the items in the collection. Contained collections (except string) are expanded /// recursively. /// /// The string representation of the collection. public override string ToString() { return Algorithms.ToString(this); } /// /// Returns a string representation of this collection. /// /// The format. /// The format provider. /// public virtual string ToString(string format, IFormatProvider formatProvider) { return Showing.ShowString(this, format, formatProvider); } #region ICollection Members /// /// Must be overridden to allow adding items to this collection. /// ///

This method is not abstract, although derived classes should always /// override it. It is not abstract because some derived classes may wish to reimplement /// Add with a different return type (typically bool). In C#, this can be accomplished /// with code like the following:

/// /// public class MyCollection<T>: CollectionBase<T>, ICollection<T> /// { /// public new bool Add(T item) { /// /* Add the item */ /// } /// /// void ICollection<T>.Add(T item) { /// Add(item); /// } /// } /// ///
/// Item to be added to the collection. /// Always throws this exception to indicated /// that the method must be overridden or re-implemented in the derived class. public virtual void Add(T item) { if (item == null) throw new InconsistencyException("Adding 'null' to the collection is not allowed."); if (mReadOnly) throw new InconsistencyException("The collection is read only"); this.innerList.Add(item); RaiseOnItemAdded(item); } /// /// Determines the index of a specific item in the . /// /// The object to locate in the . /// /// The index of item if found in the list; otherwise, -1. /// public int IndexOf(T item) { return this.innerList.IndexOf(item); } /// /// Inserts the specified item at the specified index. /// /// The index. /// A parameter of the generics Type T public virtual void Insert(int index, T item) { if (mReadOnly) throw new InconsistencyException("The collection is read only"); if (item.Equals(default(T))) return; this.innerList.Insert(index, item); RaiseOnItemAdded(item); } /// /// Adds a collection range to this collection. /// /// The items. public virtual void AddRange(CollectionBase items) { if (mReadOnly) throw new InconsistencyException("The collection is read only"); this.innerList.AddRange(items); foreach (T item in items) { RaiseOnItemAdded(item); } } private void RaiseOnItemAdded(T item) { if (OnItemAdded != null) OnItemAdded(this, new CollectionEventArgs(item)); } private void RaiseOnItemRemoved(T item) { if (OnItemRemoved != null) OnItemRemoved(this, new CollectionEventArgs(item)); } private void RaiseOnClear() { if (OnClear != null) OnClear(this, EventArgs.Empty); } /// /// Must be overridden to allow clearing this collection. /// public virtual void Clear() { RaiseOnClear(); innerList.Clear(); } /// /// Must be overridden to allow removing items from this collection. /// /// True if existed in the collection and /// was removed. False if did not exist in the collection. public virtual bool Remove(T item) { bool result = this.innerList.Remove(item); if (result) { RaiseOnItemRemoved(item); } return result; } /// /// Determines if the collection contains a particular item. This default implementation /// iterates all of the items in the collection via GetEnumerator, testing each item /// against using IComparable<T>.Equals or /// Object.Equals. /// /// You should strongly consider overriding this method to provide /// a more efficient implementation, or if the default equality comparison /// is inappropriate. /// The item to check for in the collection. /// True if the collection contains , false otherwise. public virtual bool Contains(T item) { return this.innerList.Contains(item); } /// /// Copies all the items in the collection into an array. Implemented by /// using the enumerator returned from GetEnumerator to get all the items /// and copy them to the provided array. /// /// Array to copy to. /// Starting index in to copy to. public virtual void CopyTo(T[] array, int arrayIndex) { int count = this.Count; if (count == 0) return; if (array == null) throw new ArgumentNullException("array"); if (count < 0) throw new ArgumentOutOfRangeException("count", count, Resource1.ArgumentOutOfRange); if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex", arrayIndex, Resource1.ArgumentOutOfRange); if (arrayIndex >= array.Length || count > array.Length - arrayIndex) throw new ArgumentException("arrayIndex", Resource1.ArrayTooSmall); int index = arrayIndex, i = 0; foreach (T item in (ICollection)this) { if (i >= count) break; array[index] = item; ++index; ++i; } } /// /// Creates an array of the correct size, and copies all the items in the /// collection into the array, by calling CopyTo. /// /// An array containing all the elements in the collection, in order. public virtual T[] ToArray() { int count = this.Count; T[] array = new T[count]; CopyTo(array, 0); return array; } /// /// Must be overridden to provide the number of items in the collection. /// /// The number of items in the collection. public virtual int Count { get { return innerList.Count; } } #endregion #region Delegate operations /// /// Determines if the collection contains any item that satisfies the condition /// defined by . /// /// A delegate that defines the condition to check for. /// True if the collection contains one or more items that satisfy the condition /// defined by . False if the collection does not contain /// an item that satisfies . public virtual bool Exists(Predicate predicate) { if (predicate == null) throw new ArgumentNullException("predicate"); return Algorithms.Exists(this, predicate); } /// /// Determines if all of the items in the collection satisfy the condition /// defined by . /// /// A delegate that defines the condition to check for. /// True if all of the items in the collection satisfy the condition /// defined by , or if the collection is empty. False if one or more items /// in the collection do not satisfy . public virtual bool TrueForAll(Predicate predicate) { if (predicate == null) throw new ArgumentNullException("predicate"); return Algorithms.TrueForAll(this, predicate); } /* /// /// Counts the number of items in the collection that satisfy the condition /// defined by . /// /// A delegate that defines the condition to check for. /// The number of items in the collection that satisfy . public virtual int CountWhere(Predicate predicate) { if (predicate == null) throw new ArgumentNullException("predicate"); return Algorithms.CountWhere(this, predicate); } */ /// /// Finds the first item in the collection satisfying the given predicate /// /// a searching predictae /// an item satisfying the criteria (if any) public virtual T Find(Predicate predicate) { foreach (T item in this.innerList) { if (predicate(item)) return item; } return default(T); } /// /// Removes all the items in the collection that satisfy the condition /// defined by . /// /// A delegate that defines the condition to check for. /// Returns a collection of the items that were removed, in sorted order. public virtual ICollection RemoveAll(Predicate predicate) { if (predicate == null) throw new ArgumentNullException("predicate"); return Algorithms.RemoveWhere(this, predicate); } /// /// Performs the specified action on each item in this collection. /// /// An Action delegate which is invoked for each item in this collection. public virtual void ForEach(Action action) { if (action == null) throw new ArgumentNullException("action"); Algorithms.ForEach(this, action); } #endregion #region IEnumerable Members /// /// Must be overridden to enumerate all the members of the collection. /// /// A generic IEnumerator<T> that can be used /// to enumerate all the items in the collection. public virtual IEnumerator GetEnumerator() { return this.innerList.GetEnumerator(); } #endregion #region ICollection Members /// /// Copies all the items in the collection into an array. Implemented by /// using the enumerator returned from GetEnumerator to get all the items /// and copy them to the provided array. /// /// Array to copy to. /// Starting index in to copy to. void ICollection.CopyTo(Array array, int index) { int count = this.Count; if (count == 0) return; if (array == null) throw new ArgumentNullException("array"); if (index < 0) throw new ArgumentOutOfRangeException("index", index, Resource1.ArgumentOutOfRange); if (index >= array.Length || count > array.Length - index) throw new ArgumentException("index", Resource1.ArrayTooSmall); int i = 0; foreach (object o in (ICollection)this) { if (i >= count) break; array.SetValue(o, index); ++index; ++i; } } /// /// Indicates whether the collection is synchronized. /// /// Always returns false, indicating that the collection is not synchronized. bool ICollection.IsSynchronized { get { return IsSynchronized; } } /// /// See code analysis CA1033 /// protected bool IsSynchronized { get { return false; } } /// /// Indicates the synchronization object for this collection. /// /// Always returns this. object ICollection.SyncRoot { get { return SyncRoot; } } /// /// See code analysis CA1033 /// protected object SyncRoot { get { return this; } } #endregion #region IEnumerable Members /// /// Provides an IEnumerator that can be used to iterate all the members of the /// collection. This implementation uses the IEnumerator<T> that was overridden /// by the derived classes to enumerate the members of the collection. /// /// An IEnumerator that can be used to iterate the collection. IEnumerator IEnumerable.GetEnumerator() { foreach (T item in this) { yield return item; } } #endregion /// /// Display the contents of the collection in the debugger. This is intentionally private, it is called /// only from the debugger due to the presence of the DebuggerDisplay attribute. It is similar /// format to ToString(), but is limited to 250-300 characters or so, so as not to overload the debugger. /// /// The string representation of the items in the collection, similar in format to ToString(). internal string DebuggerDisplayString() { const int MAXLENGTH = 250; System.Text.StringBuilder builder = new System.Text.StringBuilder(); builder.Append('{'); // Call ToString on each item and put it in. bool firstItem = true; foreach (T item in this) { if (builder.Length >= MAXLENGTH) { builder.Append(",..."); break; } if (!firstItem) builder.Append(','); if (item == null) builder.Append("null"); else builder.Append(item.ToString()); firstItem = false; } builder.Append('}'); return builder.ToString(); } /// /// Removes an item at the given index /// /// public void RemoveAt(int index) { this.innerList.RemoveAt(index); } /// /// Integer indexer /// /// /// public T this[int index] { get { return this.innerList[index]; } set { this.innerList[index] = value; } } /// /// Returns a deep copy of this collection. /// The returned collection is not attached to the /// and is as such on an in-memory collection of instances. You need to 'unwrap' the collection /// in the model and, to make it visible, deploy it in the paintables collection of the model. /// /// /// public CollectionBase DeepCopy() { /* This doesn't work seemingly.... if (!typeof(T).IsSerializable) throw new InconsistencyException("The generic type on which the collection is based is not serializable, the collection cannot generate a deep copy."); */ try { CollectionBase newobj = null; MemoryStream stream = new MemoryStream(); GenericFormatter f = new GenericFormatter(); f.Serialize(stream, this); stream.Seek(0, SeekOrigin.Begin); newobj = f.Deserialize>(stream); stream.Close(); return newobj; } catch (Exception exc) { throw new InconsistencyException("The copy operation failed.", exc); } } /// /// Returns a copy of this instance. /// /// public CollectionBase Copy() { CollectionBase copy = new CollectionBase(); foreach (T item in this.innerList) { copy.Add(item); } return copy; } /// /// This method creates first a deep copy of the collection and puts /// the result in a . /// See the for details. /// /// public MemoryStream ToStream() { try { MemoryStream stream = new MemoryStream(); GenericFormatter f = new GenericFormatter(); f.Serialize(stream, this); return stream; } catch (Exception exc) { throw new InconsistencyException( "The ToStream() operation failed.", exc); } } /// /// Format this using at most approximately rest chars and /// append the result, possibly truncated, to stringbuilder. /// Subtract the actual number of used chars from rest. /// /// /// /// /// /// True if the appended formatted string was complete (not truncated). /// public virtual bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider) { return true; } } }