// =====================================================================================
// Copyright © 2005 by . All rights are reserved.
//
// If you like this code then feel free to go ahead and use it.
// The only thing I ask is that you don't remove or alter my copyright notice.
//
// Your use of this software is entirely at your own risk. I make no claims or
// warrantees about the reliability or fitness of this code for any particular purpose.
// If you make changes or additions to this code please mark your code as being yours.
//
// website , email OmarALZabir@gmail.com, msn oazabir@hotmail.com
// =====================================================================================
using System.ComponentModel;
using System.Collections;
using System;
using System.Diagnostics;
using System.Xml.Serialization;
namespace SmartInstitute
{
///<summary>
/// This class is a strong typed collection of <see cref="Course"/> objects that support sorting and binding.
/// <remarks>
/// It implements the IClonable, IBindingList and IList interfaces.
/// </remarks>
///</summary>
[Serializable]
public class CourseCollectionBase : CollectionBase , IBindingList, IList, ICloneable
{
private ArrayList _SortedList = new ArrayList();
private ArrayList _OriginalList;
private bool _issorted = false;
private PropertyDescriptor _sortby;
private ListSortDirection _sortdirection = ListSortDirection.Descending;
#region "ListItem"
private class ListItem : IComparable
{
/// <summary>
/// The Key of the List Item.
/// </summary>
public object Key;
/// <summary>
/// The Item associated with the key.
/// </summary>
public object Item;
/// <summary>
/// Creates a new <see cref="ListItem"/> instance.
/// </summary>
/// <param name="key">Key.</param>
/// <param name="item">Item.</param>
public ListItem(object key, object item)
{
Key = key;
Item = item;
}
///<summary>
/// Compares the current instance with another object of the same type.
///</summary>
///<param name="obj">An object to compare with this instance.</param>
///<returns>
/// A 32-bit signed integer that indicates the relative order of the comparands. The return value has these meanings:
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <description>Meaning</description>
/// </listheader>
/// <item>
/// <term>Less than zero</term>
/// <description>This instance is less than obj.</description>
/// </item>
/// <item>
/// <term>Zero</term>
/// <description>This instance is equal to obj.</description>
/// </item>
/// <item>
/// <term>Greater than zero</term>
/// <description>This instance is greater than obj.</description>
/// </item>
/// </list>
///</returns>
int IComparable.CompareTo(object obj)
{
object target = ((ListItem)obj).Key;
if(Key is IComparable)
{
return ((IComparable)Key).CompareTo(target);
}
else
{
//Debug.WriteLine("No Comparable");
if(Key.Equals(target))
return 0;
else
return Key.ToString().CompareTo(target.ToString());
}
}
///<summary>
/// Obtains the <see cref="System.String"/> representation of this instance.
///</summary>
///<returns>The key of the item.</returns>
public override string ToString()
{
return Key.ToString ();
}
}
#endregion
#region "Find"
///<summary>
/// Finds the first <see cref="Course" /> object in the current list matching the search criteria.
///</summary>
/// <param name="searchfield">Field of the object to search.</param>
/// <param name="searchvalue">Value to find.</param>
public Course Find(CourseColumns searchfield, object searchvalue)
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(Course));
PropertyDescriptor searchby = null;
switch(searchfield)
{
case CourseColumns.ID:
searchby = props["ID"];
break;
case CourseColumns.CourseCode:
searchby = props["CourseCode"];
break;
case CourseColumns.Title:
searchby = props["Title"];
break;
case CourseColumns.SciCredit:
searchby = props["SciCredit"];
break;
case CourseColumns.CompCredit:
searchby = props["CompCredit"];
break;
case CourseColumns.LecCredit:
searchby = props["LecCredit"];
break;
case CourseColumns.ChangeStamp:
searchby = props["ChangeStamp"];
break;
}
int j = ((IBindingList)this).Find(searchby, searchvalue);
if (j > -1)
return this[j];
else
return null;
}
///<summary>
/// Finds a collection of <see cref="Course" /> objects in the current list.
///</summary>
/// <param name="searchfield">Field of the object to search.</param>
/// <param name="searchvalue">Value to find.</param>
public CourseCollection FindAll(CourseColumns searchfield, object searchvalue)
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(Course));
PropertyDescriptor searchby = null;
switch(searchfield)
{
case CourseColumns.ID:
searchby = props["ID"];
break;
case CourseColumns.CourseCode:
searchby = props["CourseCode"];
break;
case CourseColumns.Title:
searchby = props["Title"];
break;
case CourseColumns.SciCredit:
searchby = props["SciCredit"];
break;
case CourseColumns.CompCredit:
searchby = props["CompCredit"];
break;
case CourseColumns.LecCredit:
searchby = props["LecCredit"];
break;
case CourseColumns.ChangeStamp:
searchby = props["ChangeStamp"];
break;
}
CourseCollection copy = new CourseCollection();
foreach(Course _Course in this.List)
{
if (searchby.GetValue(_Course).Equals(searchvalue))
{
Course copyCourse = (Course)MakeCopyOf(_Course);
copy.Add(copyCourse);
}
}
return copy;
}
#endregion
#region "Sort Code"
///<summary>
/// Sorts the elements in the CourseCollectionBase .
///</summary>
private void SortList()
{
_SortedList.Clear();
//Load List to sort.
if (_sortby == null)
{
foreach(object obj in this.InnerList)
{
_SortedList.Add(new ListItem(obj,obj));
}
}
else
{
foreach(object obj in this.InnerList)
{
_SortedList.Add(new ListItem(_sortby.GetValue(obj), obj));
}
}
//if not already sorted, create a backup of original
if(!_issorted)
_OriginalList = new ArrayList(List);
//Sort List
_SortedList.Sort();
//Clear real list.
InnerList.Clear();
//re-add item in sorted order.
if(_sortdirection == ListSortDirection.Ascending)
{
for(int x=0; x < _SortedList.Count;x++)
{
base.InnerList.Add(((ListItem)_SortedList[x]).Item );
}
}
else
{
for(int x=_SortedList.Count-1; x != -1;x--)
{
base.InnerList.Add(((ListItem)_SortedList[x]).Item );
}
}
_issorted = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset,0));
}
/// <summary>
/// Sorts the collection based upon field selected.
/// </summary>
/// <param name="field">Field of the object on which to sort.</param>
/// <param name="direction">Direction to sort in, Ascending or Descending.</param>
public void Sort(CourseColumns field, ListSortDirection direction)
{
this._sortby = TypeDescriptor.GetProperties(typeof(Course)).Find( field.ToString(), false );
this._sortdirection = direction;
SortList();
}
/// <summary>
/// Sorts the collection based on primary key.
/// </summary>
/// <param name="direction">Direction to sort in, Ascending or Descending.</param>
public void Sort(ListSortDirection direction)
{
_sortby = null;
_sortdirection = direction;
SortList();
}
/// <summary>
/// Sorts the collection based on primary key. Sorts in Ascending order.
/// </summary>
public void Sort()
{
_sortby = null;
_sortdirection = ListSortDirection.Ascending;
SortList();
}
#endregion
#region Shuffle
/// <summary>
/// Sorts the collection based on a random shuffle.
/// </summary>
/// <author>Steven Smith</author>
/// <url>http://blogs.aspadvice.com/ssmith/archive/2005/01/27/2480.aspx</url>
public void Shuffle()
{
ArrayList source = this.InnerList;
Random rnd = new Random();
for (int inx = source.Count-1; inx > 0; inx--)
{
int position = rnd.Next(inx+1);
object temp = source[inx];
source[inx] = source[position];
source[position] = temp;
}
}
#endregion
#region Typed Collection Methods
/// <summary>
/// Adds a new Course instance to the Collection.
/// </summary>
/// <param name="value"><see cref="Product"/> instance.</param>
/// <returns></returns>
public int Add (Course value)
{
return List.Add(value);
}
/// <summary>
/// Adds a new Course instance to the Collection.
/// </summary>
///<param name="ID"></param>
///<param name="CourseCode"></param>
///<param name="Title"></param>
///<param name="SciCredit"></param>
///<param name="CompCredit"></param>
///<param name="LecCredit"></param>
///<param name="ChangeStamp"></param>
/// <returns></returns>
public int Add (System.Int32 ID, System.String CourseCode, System.String Title, System.Int32 SciCredit, System.Int32 CompCredit, System.Int32 LecCredit, System.DateTime ChangeStamp)
{
return List.Add(new Course(ID, CourseCode, Title, SciCredit, CompCredit, LecCredit, ChangeStamp));
}
/// <summary>
/// Adds a new Course to the Collection.
/// </summary>
/// <returns>Product object.</returns>
public Course AddNew()
{
return (Course)((IBindingList)this).AddNew();
}
/// <summary>
/// Gets or sets the <see cref="Course"/> at the specified index.
/// </summary>
/// <value></value>
public Course this[int index]
{
get
{
return (Course)(List[index]);
}
set
{
List[index] = value;
}
}
/// <summary>
/// Removes a Course object from the Collection.
/// </summary>
/// <param name="value">Product object.</param>
public void Remove (Course value)
{
List.Remove(value);
}
#endregion
#region "Typed Event Handlers"
private ListChangedEventArgs resetEvent = new ListChangedEventArgs(ListChangedType.Reset, -1);
private ListChangedEventHandler onListChanged;
/// <summary>
/// Raises the ListChanged event.
/// </summary>
/// <param name="ev">A <see cref="ListChangedEventArgs"/> that contains the event data.</param>
protected virtual void OnListChanged(ListChangedEventArgs ev)
{
if (onListChanged != null)
{
onListChanged(this, ev);
}
}
/// <summary>
/// Raises the ListChanged event.
/// </summary>
protected override void OnClearComplete()
{
if(_issorted)
_OriginalList.Clear();
OnListChanged(resetEvent);
}
/// <summary>
/// Raises the InsertComplete event.
/// Performs additional custom processes after inserting a new element into the CourseCollectionBase instance.
/// </summary>
/// <param name="index">The zero-based index at which to insert value.</param>
/// <param name="value">The new value of the element at index.</param>
protected override void OnInsertComplete(int index, object value)
{
if(_issorted)
_OriginalList.Add(value);
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
}
/// <summary>
/// Raises the RemoveComplete event.
/// Performs additional custom processes after removing a new element into the CourseCollectionBase instance.
/// </summary>
/// <param name="index">The zero-based index at which value can be found.</param>
/// <param name="value">The value of the element to remove from index.</param>
protected override void OnRemoveComplete(int index, object value)
{
if(_issorted)
_OriginalList.Remove(value);
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
}
/// <summary>
/// Raises the SetComplete event.
/// Performs additional custom processes after setting a value in the CourseCollectionBase instance.
/// </summary>
/// <param name="index">The zero-based index at which oldValue can be found.</param>
/// <param name="oldValue">The value to replace with newValue.</param>
/// <param name="newValue">The new value of the element at index.</param>
protected override void OnSetComplete(int index, object oldValue, object newValue)
{
if (oldValue != newValue)
{
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));
}
}
#endregion "Typed Event Handlers"
#region "IBindingList"
///<summary>
/// Gets whether you can update items in the list.
///</summary>
bool IBindingList.AllowEdit
{
get { return true ; }
}
///<summary>
/// Gets whether you can add items to the list using <see cref="IBindingList.AddNew"/>.
///</summary>
bool IBindingList.AllowNew
{
get { return true ; }
}
///<summary>
/// Gets whether you can remove items from the list, using <see cref="IList.Remove"/> or <see cref="IList.RemoveAt"/>.
///</summary>
bool IBindingList.AllowRemove
{
get { return true ; }
}
///<summary>
/// Gets whether a <see cref="ListChanged"/> event is raised when the list changes or an item in the list changes.
///</summary>
bool IBindingList.SupportsChangeNotification
{
get { return true ; }
}
///<summary>
/// Gets whether the list supports searching using the <see cref="IBindingList.Find"/> method.
///</summary>
bool IBindingList.SupportsSearching
{
get { return true ; }
}
///<summary>
/// Gets whether the list supports sorting.
///</summary>
bool IBindingList.SupportsSorting
{
get { return true ; }
}
///<summary>
/// Gets whether the items in the list are sorted.
///</summary>
bool IBindingList.IsSorted
{
get { return _issorted; }
}
///<summary>
/// Gets the direction of the sort.
///</summary>
ListSortDirection IBindingList.SortDirection
{
get { return _sortdirection; }
}
///<summary>
/// Gets the <see cref="PropertyDescriptor"/> that is being used for sorting.
///</summary>
PropertyDescriptor IBindingList.SortProperty
{
get { return _sortby; }
}
///<summary>
/// Returns the index of the row that has the given <see cref="PropertyDescriptor"/>.
///</summary>
///<param name="property">The <see cref="PropertyDescriptor"/> to search on. </param>
///<param name="key">The value of the property parameter to search for.</param>
///<returns>The index of the row that has the given <see cref="PropertyDescriptor"/>.</returns>
int IBindingList.Find(PropertyDescriptor property, object key)
{
foreach(Course _Course in this.List)
{
if (property.GetValue(_Course).Equals(key))
return this.List.IndexOf(_Course);
}
return -1;
}
///<summary>
/// Occurs when the list managed by the <see cref="CourseCollection"/> changes.
///</summary>
public event ListChangedEventHandler ListChanged
{
add
{
onListChanged += value;
}
remove
{
onListChanged -= value;
}
}
// Methods.
///<summary>
/// Adds a new item to the list.
///</summary>
///<returns>The item added to the list.</returns>
object IBindingList.AddNew()
{
Course c = new Course();
List.Add(c);
return c;
}
///<summary>
/// Sorts the list based on a <see cref="PropertyDescriptor"/> and a <see cref="ListSortDirection"/>.
///</summary>
///<param name="property">The <see cref="PropertyDescriptor"/> to sort by.</param>
///<param name="direction">One of the <see cref="ListSortDirection"/> values.</param>
void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction)
{
_sortby = property;
_sortdirection = direction;
SortList();
}
///<summary>
/// Removes any sort applied using <see cref="IBindingList.ApplySort"/>.
///</summary>
public void RemoveSort()
{
if(_issorted)
{
base.InnerList.Clear();
foreach(object obj in _OriginalList)
base.InnerList.Add(obj);
_issorted = false;
_OriginalList = null; //destroy
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset,0));
}
}
#region "Unsupported Methods"
///<summary>
/// Adds the <see cref="PropertyDescriptor"/> to the indexes used for searching.
///</summary>
///<param name="property">The <see cref="PropertyDescriptor"/> to add to the indexes used for searching.</param>
///<remarks>The list must support this method. However, support for this method can be a nonoperation.</remarks>
///<exception cref="System.NotSupportedException">Thrown</exception>
void IBindingList.AddIndex(PropertyDescriptor property)
{
throw new NotSupportedException();
}
///<summary>
/// Removes the <see cref="PropertyDescriptor"/> from the indexes used for searching.
///</summary>
///<param name="property">The <see cref="PropertyDescriptor"/> to remove from the indexes used for searching.</param>
///<exception cref="System.NotSupportedException">Thrown</exception>
void IBindingList.RemoveIndex(PropertyDescriptor property)
{
throw new NotSupportedException();
}
#endregion "Unsupported Methods"
#endregion "IBindingList"
#region "ICloneable"
///<summary>
/// Creates an exact copy of this <see cref="CourseCollection"/> object.
///</summary>
///<returns>The <see cref="CourseCollection"/> object this method creates, cast as an object.</returns>
///<implements><see cref="ICloneable.Clone"/></implements>
public object Clone(){
return this.Copy();
}
///<summary>
/// Creates an exact copy of this <see cref="CourseCollection"/> object.
///</summary>
///<returns>A new, identical copy of the <see cref="CourseCollection"/>.</returns>
public virtual CourseCollection Copy(){
CourseCollection copy = new CourseCollection();
foreach(Course _Course in this.List)
{
Course copyCourse = (Course)MakeCopyOf(_Course);
copy.Add(copyCourse);
}
return copy;
}
///<summary>
/// Creates an exact copy of this <see cref="CourseCollection"/> object.
///</summary>
///<returns>A new, identical copy of the <see cref="CourseCollection"/> casted as object.</returns>
public static object MakeCopyOf(object x)
{
if (x is ICloneable)
{
// Return a deep copy of the object
return ((ICloneable)x).Clone();
}
else
{
throw new
System.NotSupportedException("object not cloneable");
}
}
#endregion "ICloneable"
#region "Added Functionality"
/// <summary>
/// Returns the number of items that have been marked new in the collection.
/// </summary>
///<returns>the number of items that have been marked new in the collection</returns>
public int IsNewCount
{
get
{
int count = 0;
foreach(Course p in this.List)
{
if(p.IsNew)
count += 1;
}
return count;
}
}
/// <summary>
/// Returns the number of items that have been marked as modified in the collection.
/// </summary>
///<returns>the number of items that have been marked as modified in the collection</returns>
public int IsDirtyCount
{
get
{
int count = 0;
foreach(Course p in this.List)
{
if(p.IsDirty)
count += 1;
}
return count;
}
}
#endregion "Added Functionality"
///<summary>
/// Returns a String that represents the current CourseCollection.
///</summary>
public override string ToString()
{
string output = string.Format("There is {0} Course object in this collection{1}{1}", this.List.Count, Environment.NewLine);
foreach(Course p in this.List)
{
output += p.ToString();
}
return output;
}
}
}