/*
* Namespace Summary
* Copyright (C) 2005+ Bogdan Damian Constantin
* E-Mail: damianbcpetro@gmail.com
* WEB: http://www.sourceforge.net/projects/dataholder
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License 2.1 or later, as
* published by the Free Software Foundation. See the included License.txt
* or http://www.gnu.org/copyleft/lesser.html for details.
*
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using DataHolder.Containers.Property;
namespace DataHolder.Containers{
public delegate void SortChangedDelegate(Property.GenericDataProperty property, ListSortDirection direction);
public enum GenericDataCollectionViewState { Current = 1, All = 2 };
public abstract class BaseGenericDataCollectionView:IDisposable, IBindingList, ITypedList
{
public event GenericDataCollectionModified CollectionModified;
public event GenericDataPropertyModified PropertyModified;
public event SortChangedDelegate SortChanged;
#region constructors
public BaseGenericDataCollectionView(GenericDataCollection gecoll)
{
l_AllowNew = false;
lIsSorted = false;
lAllowRemove = false;
lAllowEdit = false;
lGEEntitiesState = GenericDataCollectionViewState.Current;
innerCollection = gecoll;
Initialize();
}
protected void Initialize()
{
SetPositions();
innerCollection.CollectionModified += new GenericDataCollectionModified(innerCollection_CollectionModified);
innerCollection.PropertyModified += new GenericDataPropertyModified(innerCollection_PropertyModified);
}
#endregion
protected GenericDataCollection innerCollection;
protected bool l_AllowNew, lIsSorted, lAllowRemove, lAllowEdit;
protected ListSortDirection lSortDirection;
protected int[] Positions;
protected PropertyDescriptor lSortProperty = null;
protected GenericDataCollectionViewState lGEEntitiesState;
/// <summary>
/// states of the data that will be visible through this view
/// if you wan to see only data that is in a specific state please modify this collection
/// </summary>
public GenericDataCollectionViewState GEEntitiesState
{
get
{
return lGEEntitiesState;
}
set
{
lGEEntitiesState = value;
}
}
public System.Data.DataTable ToDataTable()
{
System.Data.DataTable tb = new System.Data.DataTable();
Property.PropertyCollection Properties = GenericData.TCollection.GetProperties(innerCollection.GenericDataType);
for(int i = 0; i < Properties.Count; i++)
tb.Columns.Add(Properties[i].PropertyName, Properties[i].PropertyType);
for(int i = 0; i < this.Count; i++)
{
System.Data.DataRow row = tb.NewRow();
for(int j = 0; j < Properties.Count; j++)
{
GenericData tmpge = innerCollection.GetObjectAt(Positions[i]);
row[j] = tmpge[j];
}
tb.Rows.Add(row);
}
return tb;
}
#region internall methods
protected void SetPositions()
{
int [] tmpPositions = new int [innerCollection.Count];
int i = 0, j = 0;
for(i = 0; i < innerCollection.Count; i++)
if(lGEEntitiesState != GenericDataCollectionViewState.Current
|| ( innerCollection.GetObjectAt(i).State != GenericDataState.Deleted
&& innerCollection.GetObjectAt(i).State != GenericDataState.Detached))
{
tmpPositions[j] = i;
j++;
}
Positions = new int [j];
for(i = 0; i < j; i++)
Positions[i] = tmpPositions[i];
tmpPositions = null;
if(lSortProperty != null)
DoSort(lSortProperty, lSortDirection);
}
protected GenericDataProperty DoSort(PropertyDescriptor property, ListSortDirection direction)
{
PropertyCollection _Properties = GenericData.TCollection.GetProperties(innerCollection.GenericDataType);
GenericDataProperty prop = _Properties[property.DisplayName];
if(prop != null)
{
CollectionComparer cc = new CollectionComparer(this, (IComparer)prop, _Properties.IndexOf(property.DisplayName));
Array.Sort(Positions,cc);
cc = null;
}
_Properties = null;
return prop;
}
protected int GetPositionBySource(int SourceCollectionIndex)
{
lock(this.innerCollection.SyncRoot)
{
for(int i = 0; i < Positions.Length; i++)
if(SourceCollectionIndex == Positions[i])
return i;
}
throw new Exception("index " + SourceCollectionIndex.ToString() +" not found");
}
#endregion
#region IDisposable Members
public void Dispose()
{
innerCollection = null;
Positions = null;
CollectionModified = null;
PropertyModified = null;
SortChanged = null;
lSortProperty = null;
}
#endregion
#region IBindingList Members
public void AddIndex(PropertyDescriptor property)
{
throw new NotSupportedException();
}
public bool AllowNew
{
get{return l_AllowNew;}
set{l_AllowNew = value;}
}
public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
{
lSortProperty = property;
lSortDirection = direction;
GenericDataProperty prop = null;
lock(this.innerCollection.SyncRoot)
{
prop = DoSort(property, direction);
}
ExecuteListChangedEvents(ListChangedType.Reset, property);
lIsSorted = true;
if(SortChanged != null)
SortChanged(prop, direction);
}
public void Sort(string ColumnName, ListSortDirection direction)
{
PropertyCollection pcol = GenericData.TCollection.GetProperties(innerCollection.GenericDataType);
GenericDataPropertyDescriptor pp = new GenericDataPropertyDescriptor(pcol, ColumnName, null);
ApplySort(pp, direction);
}
public PropertyDescriptor SortProperty
{
get
{
return lSortProperty;
}
}
#region Find Implementation
public int Find(PropertyDescriptor property, object key)
{
GenericDataPropertyDescriptor geproperty = property as GenericDataPropertyDescriptor;
if(geproperty != null)
return Find(geproperty.PropertyCollection, geproperty.PropertyIndex, key);
//for properties defined by user reflection will be used
for(int i =0 ;i < this.Count; i++)
if(property.GetValue(innerCollection.GetObjectAt(Positions[i])).Equals(key))
return i;
return 0;
}
private int Find(PropertyCollection pcoll, int PropertyIndex, object key)
{
if(pcoll[PropertyIndex] is IComparer)
{
IComparer comp = (IComparer)pcoll[PropertyIndex];
for(int i =0 ;i < this.Count; i++)
if(comp.Compare(key, (innerCollection.GetObjectAt(Positions[i]))[PropertyIndex]) == 0)
return i;
return 0;
}
else
return 0;
}
public int Find(string PropertyName, object key)
{
PropertyCollection pcoll = GenericData.TCollection.GetProperties(innerCollection.GenericDataType);
int PropertyIndex = pcoll.IndexOf(PropertyName);
#if FULLCHECKING
if(PropertyIndex < 0)
throw new DataHolder.Exceptions.DataHolderPropertyException("Can't find key " + key.ToString() + " by " + PropertyName + " because thr property doesn't exists in " + innerCollection.GenericDataType.ToString() );
#endif
return Find(pcoll, PropertyIndex, key);
}
#endregion
public bool SupportsSorting
{
get
{
return true;
}
}
public bool IsSorted
{
get
{
return lIsSorted;
}
}
public bool AllowRemove
{
get
{
return lAllowRemove;
}
set
{
lAllowRemove = value;
}
}
public bool SupportsSearching
{
get
{
return true;
}
}
public ListSortDirection SortDirection
{
get
{
return lSortDirection;
}
set
{
lSortDirection = value;
}
}
private void ExecuteListChangedEvents(ListChangedType lct, PropertyDescriptor pdesc)
{
if(ListChangedEvents != null)
{
foreach(ListChangedEventHandler lev in ListChangedEvents)
lev(this, new ListChangedEventArgs(lct, pdesc));
}
}
private void ExecuteListChangedEvents(ListChangedType lct, int index)
{
if(ListChangedEvents != null)
{
foreach(ListChangedEventHandler lev in ListChangedEvents)
lev(this, new ListChangedEventArgs(lct, index));
}
}
private ArrayList ListChangedEvents = null;
public event ListChangedEventHandler ListChanged
{
add
{
if(ListChangedEvents == null)
ListChangedEvents = new ArrayList(1);
ListChangedEvents.Add(value);
}
remove
{
ListChangedEvents.Remove(value);
if(ListChangedEvents.Count == 0)
ListChangedEvents = null;
}
}
public bool SupportsChangeNotification
{
get
{
return true;
}
}
public void RemoveSort()
{
lock (this.innerCollection.SyncRoot)
{
lSortProperty = null;
SetPositions();
}
}
public object AddNew()
{
return innerCollection.AddNew();
}
public bool AllowEdit
{
get
{
return lAllowEdit;
}
}
public void RemoveIndex(PropertyDescriptor property)
{
throw new NotSupportedException();
}
#endregion
#region IList Members
bool IList.IsReadOnly
{
get
{
return false;
}
}
object IList.this[int index]
{
get
{
return innerCollection.GetObjectAt(Positions[index]);
}
set
{
innerCollection.SetObjectAt(Positions[index], (GenericData)value);
}
}
public void RemoveAt(int index)
{
innerCollection.RemoveAt(Positions[index]);
}
void IList.Insert(int index, object value)
{
innerCollection.Insert(Positions[index], (GenericData)value);
}
void IList.Remove(object value)
{
innerCollection.Remove((GenericData)value);
}
bool IList.Contains(object value)
{
return innerCollection.Contains((GenericData)value);
}
public void Clear()
{
innerCollection.Clear();
}
int IList.IndexOf(object value)
{
for(int i = 0; i < Positions.Length; i++)
if(value == innerCollection.GetObjectAt(Positions[i]))
return i;
return -1;
}
int IList.Add(object value)
{
innerCollection.Add((GenericData)value);
return 1;
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
#endregion
#region ICollection Members
public bool IsSynchronized
{
get
{
return true;
}
}
public int Count
{
get
{
return Positions.Length;
}
}
void ICollection.CopyTo(Array array, int index)
{
innerCollection.CopyTo((GenericData[])array, index);
}
public object SyncRoot
{
get
{
return this;
}
}
#endregion
#region IEnumerable Members
public System.Collections.IEnumerator GetEnumerator()
{
return new GenericDataEnumerator(this);
}
#endregion
#region CollectionComparer
internal class CollectionComparer : IComparer
{
private BaseGenericDataCollectionView colview;
private IComparer _gep;
private int _Position;
public CollectionComparer(BaseGenericDataCollectionView cv, IComparer gep, int Position)
{
colview = cv;
_gep = gep;
_Position = Position;
}
public int Compare(object x, object y)
{
object ox = colview.innerCollection.GetObjectAt((int)x)[_Position];
object oy = colview.innerCollection.GetObjectAt((int)y)[_Position];
int XGraterthanY = _gep.Compare(ox, oy);
if(colview.SortDirection == System.ComponentModel.ListSortDirection.Ascending)
return XGraterthanY;
else
return XGraterthanY * -1;
}
}
#endregion
#region ITypedList Members
private void ClearInternalPropertiesFromPropertyDescriptor(ArrayList pdc)
{
for(int pi = pdc.Count -1; pi >= 0; pi--)
{
PropertyDescriptor p = (PropertyDescriptor)pdc[pi];
if(p.Name.Equals("SuppressEvents")
|| p.Name.Equals("Properties")
|| p.Name.Equals("Parent")
|| p.Name.Equals("NewPropertyCollection"))
pdc.RemoveAt(pi);
}
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
PropertyDescriptorCollection pdctmp = TypeDescriptor.GetProperties(innerCollection.GenericDataType);
ArrayList pdc = new ArrayList(pdctmp.Count);
ClearInternalPropertiesFromPropertyDescriptor(pdc);
pdc.AddRange(pdctmp);
PropertyCollection pcol = GenericData.TCollection.GetProperties(innerCollection.GenericDataType);
PropertyDescriptor [] pdesccollection = new PropertyDescriptor[pcol.Count];
for(int i = 0; i < pcol.Count; i++)
{
pdesccollection[i] = new GenericDataPropertyDescriptor(pcol, pcol[i].PropertyName,null);
for(int pi = 0; pi < pdc.Count; pi++)
if(pcol[i].PropertyName.Equals(((PropertyDescriptor)pdc[pi]).Name))
{
pdc.RemoveAt(pi);
break;
}
}
PropertyDescriptor [] res = new PropertyDescriptor[pcol.Count+pdc.Count];
pdesccollection.CopyTo(res,0);
pdc.CopyTo(res, pdesccollection.Length);
return new PropertyDescriptorCollection(res);
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
return string.Empty;
}
#endregion
#region Events Action
private void innerCollection_CollectionModified(GenericData ge, GenericDataCollectionEventType evType, int index)
{
lock(this.SyncRoot)
{
if(evType == GenericDataCollectionEventType.Clear)
{
SetPositions();
ExecuteListChangedEvents(ListChangedType.Reset,0);
if(CollectionModified != null)
CollectionModified(ge, evType, 0);
return;
}
else
{
int position = -1;
if(evType == GenericDataCollectionEventType.Deleted)
position = GetPositionBySource(index);
SetPositions();
if(evType == GenericDataCollectionEventType.Added)
{
if(lGEEntitiesState == GenericDataCollectionViewState.All
|| ge.State != GenericDataState.Detached)
{
position = GetPositionBySource(index);
ExecuteListChangedEvents(ListChangedType.ItemAdded,position);
}
}
else if(evType == GenericDataCollectionEventType.Modified)
{
position = GetPositionBySource(index);
ExecuteListChangedEvents(ListChangedType.ItemChanged,position);
}
else if(evType == GenericDataCollectionEventType.Deleted)
ExecuteListChangedEvents(ListChangedType.ItemDeleted,position);
if(evType != GenericDataCollectionEventType.Reset
&& CollectionModified != null)
CollectionModified(ge, evType, position);
}
}
}
private void innerCollection_PropertyModified(GenericData ge, GEChangeEventArgs args)
{
lock(this.innerCollection.SyncRoot)
{
if(SortProperty != null)
DoSort(SortProperty, SortDirection);
ExecuteListChangedEvents(ListChangedType.ItemChanged, ((IList)this).IndexOf(ge));
if(PropertyModified != null)
PropertyModified(ge,args);
}
}
#endregion
}
}
|