/*
* 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.Data;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Runtime.Serialization;
using DataHolder.Containers.Property;
using DataHolder.Containers.ParentActions;
using DataHolder.DataPersistence.DBAProvider;
namespace DataHolder.Containers{
public enum GenericDataVersion{Current = 1, Original = 2, Intermediar = 3};
public enum GenericDataState{Added = 1, Deleted = 2, Detached = 3,Modified = 4, Unchanged = 5};
/// <summary>
/// Generic data is the base class for all dataholder related persistence options
/// </summary>
[Serializable]
public abstract class GenericData : IEditableObject, IDisposable, ParentActions.IGenericDataParent, ITypedList, ISerializable, IXmlSerializable
{
protected object [] lValues = null;
protected object [] lOriginalValues;
protected object [] lIntermediarValues;
protected Property.PropertyCollection lProperties;
protected GenericDataState lState;
protected ParentActions.IGenericDataParent lParent;
private bool lInEdit = false;
private bool lSuppressEvents = false;
#region Events
/// <summary>
/// FIred when a property value is changed
/// </summary>
public event GenericDataPropertyModified PropertyModified;
#endregion
#region Contructors
public GenericData()
{
lProperties = TCollection.GetProperties(this);
InitDataValues();
}
public GenericData(GenericData lge)
{
lProperties = lge.lProperties;
lValues = new object[lProperties.Count];
lState = lge.State;
}
#endregion
#region Item property
public object this[string ColumnName]
{
get
{
return lValues[lProperties.IndexOf(ColumnName)];
}
set
{
this[lProperties.IndexOf(ColumnName)] = value;
}
}
public object this[string ColumnName, GenericDataVersion vers]
{
get
{
return this[lProperties.IndexOf(ColumnName), vers];
}
}
public object this[int PropertyIndex, GenericDataVersion vers]
{
get
{
if(lSuppressEvents || lProperties[PropertyIndex] is Property.TypedProperty)
return lValues[PropertyIndex];
else if(vers == GenericDataVersion.Current)
return this[PropertyIndex];
else if(vers == GenericDataVersion.Intermediar)
{
if(lIntermediarValues != null)
return lIntermediarValues[PropertyIndex];
else
return this[PropertyIndex];
}
else if(vers == GenericDataVersion.Original)
{
if(lOriginalValues != null)
return lOriginalValues[PropertyIndex];
else
return this[PropertyIndex];
}
else
throw new Exception("Invalid GenericDataVersion");
}
set
{
if(vers == GenericDataVersion.Current)
this[PropertyIndex] = value;
else if(vers == GenericDataVersion.Intermediar)
{
if(lIntermediarValues == null)
lIntermediarValues = new object[lProperties.Count];
lIntermediarValues[PropertyIndex] = value;
}
else if(vers == GenericDataVersion.Original)
{
if(lOriginalValues == null)
lOriginalValues = new object[lProperties.Count];
lOriginalValues[PropertyIndex] = value;
}
}
}
public object this[int PropertyIndex]
{
get
{
return lValues[PropertyIndex];
}
set
{
//this is for supper fast loading
if(lSuppressEvents || lProperties[PropertyIndex] is Property.TypedProperty)
{
lValues[PropertyIndex] = value;
return;
}
bool DoSetValue = false;
if(lProperties[PropertyIndex] is IComparer)
{
if(((IComparer)lProperties[PropertyIndex]).Compare(value, lValues[PropertyIndex]) != 0)
DoSetValue = true;
}
else
DoSetValue = true;
if(DoSetValue)
{
if(lOriginalValues == null)
{
lOriginalValues = new object[lProperties.Count];
lValues.CopyTo(lOriginalValues,0);
}
if(!lInEdit || lIntermediarValues == null)
{
lInEdit = true;
lIntermediarValues = new object [lProperties.Count];
lValues.CopyTo(lIntermediarValues,0);
}
lValues[PropertyIndex] = value;
switch(lState)
{
case GenericDataState.Added:
break;
case GenericDataState.Detached:
break;
case GenericDataState.Modified:
break;
case GenericDataState.Unchanged:
lState = GenericDataState.Modified;
break;
case GenericDataState.Deleted:
throw new Exception("An Deleted Data can't be modified");
}
GEChangeEventArgs tmpargs = new GEChangeEventArgs(lProperties[PropertyIndex], GEChangeEventArgs.ChangeEventType.FieldChange);
if(lParent != null)
lParent.GenericDataChildModified(this, tmpargs);
if(PropertyModified != null)
PropertyModified(this, tmpargs);
}
}
}
#endregion
#region States
/// <summary>
/// Gets the Data State
/// </summary>
public GenericDataState State
{
get
{
return lState;
}
}
/// <summary>
/// if set to true the Data will not generate any events
/// </summary>
public bool SuppressEvents
{
get
{
return lSuppressEvents;
}
set
{
lSuppressEvents = value;
}
}
/// <summary>
/// returns the status of the Data if it is in edit or not
/// </summary>
public bool InEdit
{
get
{
return lInEdit;
}
}
#endregion
#region Actions
protected void InitDataValues()
{
lValues = new object[lProperties.Count];
lState = GenericDataState.Detached;
object propDefaultValue;
for(int i = 0; i < lProperties.Count; i++)
if(lProperties[i] is Property.Property)
{
propDefaultValue = ((Property.Property)lProperties[i]).PropertyDefaultValue;
if(propDefaultValue != null)
lValues[i] = propDefaultValue;
else
lValues[i] = DBNull.Value;
}
else if(lProperties[i] is Property.TypedProperty)
{
Property.TypedProperty tmprop = (Property.TypedProperty)lProperties[i];
if(tmprop.AutoCreate)
{
IGenericDataParent newobj = (IGenericDataParent)Activator.CreateInstance(tmprop.PropertyType);
newobj.Parent = this;
lValues[i] = newobj;
}
}
}
public void BeginEdit()
{
lInEdit = true;
}
internal void EndEdit(bool CallEvents)
{
lInEdit = false;
lIntermediarValues = null;
if(State == GenericDataState.Detached)
{
lState = GenericDataState.Added;
if(Parent != null && CallEvents)
Parent.GenericDataChildModified(this, new GEChangeEventArgs(GEChangeEventArgs.ChangeEventType.DetachedFieldAdded));
}
for(int i = 0; i < Properties.Count; i++)
if(Properties[i] is TypedProperty && this[i] is GenericData)
((GenericData)this[i]).EndEdit(CallEvents);
else if(Properties[i] is TypedProperty && this[i] is GenericDataCollection)
((GenericDataCollection)this[i]).EndEdit();
}
public void EndEdit()
{
EndEdit(true);
}
internal void CancelEdit(bool CallEvents)
{
if(lState == GenericDataState.Detached)
Delete();
else if(lInEdit == true && lIntermediarValues != null)
{
lIntermediarValues.CopyTo(lValues,0);
lIntermediarValues = null;
if(Parent != null && CallEvents)
Parent.GenericDataChildModified(this, new GEChangeEventArgs(GEChangeEventArgs.ChangeEventType.CancelEdit));
}
lInEdit =false;
for(int i = 0; i < Properties.Count; i++)
if(Properties[i] is TypedProperty && this[i] is GenericData)
((GenericData)this[i]).CancelEdit(CallEvents);
else if(Properties[i] is TypedProperty && this[i] is GenericDataCollection)
((GenericDataCollection)this[i]).CancelEdit();
}
public void CancelEdit()
{
CancelEdit(true);
}
public void AcceptChanges()
{
AcceptChanges(true);
}
public void AcceptChanges(bool CallEvents)
{
this.EndEdit(CallEvents);
lState = GenericDataState.Unchanged;
lInEdit = false;
lOriginalValues = null;
lIntermediarValues = null;
for(int i = 0; i < Properties.Count; i++)
if(Properties[i] is TypedProperty && this[i] is GenericData)
((GenericData)this[i]).AcceptChanges(CallEvents);
else if(Properties[i] is TypedProperty && this[i] is GenericDataCollection)
((GenericDataCollection)this[i]).AcceptChanges(CallEvents);
}
public void RejectChanges()
{
this.CancelEdit(true);
lState = GenericDataState.Unchanged;
lInEdit = false;
if(lOriginalValues != null)
lOriginalValues.CopyTo(lValues,0);
lOriginalValues = null;
lIntermediarValues = null;
if(Parent != null)
Parent.GenericDataChildModified(this, new GEChangeEventArgs(GEChangeEventArgs.ChangeEventType.RejectChanges));
}
public void ReNewData()
{
lState = GenericDataState.Unchanged;
lInEdit = false;
lOriginalValues = null;
lIntermediarValues = null;
InitDataValues();
if(Parent != null)
Parent.GenericDataChildModified(this, new GEChangeEventArgs(GEChangeEventArgs.ChangeEventType.RenewData));
}
public void Delete()
{
if(lState == GenericDataState.Deleted)
throw new Exception("An deleted Data can't be deleted once more");
if(lState != GenericDataState.Added && lState != GenericDataState.Detached)
lState = GenericDataState.Deleted;
if(Parent != null)
Parent.GenericDataChildModified(this, new GEChangeEventArgs(GEChangeEventArgs.ChangeEventType.Delete));
}
public void CopyValuesByPropName(GenericData source)
{
for(int cp=0;cp < this.Properties.Count; cp++)
{
int sp = source.Properties.IndexOf(this.Properties[cp].PropertyName);
if(sp >= 0 && this.Properties[cp].PropertyType == source.Properties[sp].PropertyType)
this[cp] = source[sp];
}
}
#endregion
/// <summary>
/// Properties contained pay the data holder
/// </summary>
public Property.PropertyCollection Properties
{
get
{
return lProperties;
}
}
//this is just used to hide NewPropertyCollection property
internal Property.PropertyCollection GetNewPropertyCollection()
{
return NewPropertyCollection;
}
/// <summary>
/// This property must be overrided. It returns a new property collection
/// for youre type. It's something like a controlled Constructor
/// </summary>
protected abstract Property.PropertyCollection NewPropertyCollection
{
get;
}
#region Serialization
public const string GeneralStateRegion = "GSR";
public const string StateLabel = "State_";
public const string InEditLabel = "In_Edit_";
public const string SerializationNoLabel = "Seri_No_";
public const string OriginalValuesSerializationIdentifier = "Orig_Val";
public const string IntermediarValuesSerializationIdentifier = "Interm_Val";
public const string HasOriginalValuesLabel = "HasOrig_Vals_";
internal bool InSerialization = false;
internal ulong SerializationNo = 0;
#region ISerializable Members
/// <summary>
/// Serialization Constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public GenericData(SerializationInfo info, StreamingContext context)
{
lState = (GenericDataState)info.GetInt32(StateLabel);
lInEdit = info.GetBoolean(InEditLabel);
bool HasOriginalValues = info.GetBoolean(HasOriginalValuesLabel);
lProperties = TCollection.GetProperties(this);
lValues = new object[lProperties.Count];
for(int i = 0; i < lProperties.Count; i++)
lValues[i] = info.GetValue(lProperties[i].PropertyName, lProperties[i].PropertyType);
if(HasOriginalValues)
{
lOriginalValues = new object[lProperties.Count];
for(int i = 0; i < lProperties.Count; i++)
if(!lProperties[i].PropertyType.IsByRef)
lOriginalValues[i] = info.GetValue(OriginalValuesSerializationIdentifier+lProperties[i].PropertyName, lProperties[i].PropertyType);
}
if(InEdit)
{
lIntermediarValues = new object[lProperties.Count];
for(int i = 0; i < lProperties.Count; i++)
if(!lProperties[i].PropertyType.IsByRef)
lIntermediarValues[i] = info.GetValue(IntermediarValuesSerializationIdentifier+lProperties[i].PropertyName, lProperties[i].PropertyType);
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
SerializationHelper srinfo = null;
if(!InSerialization)
{
srinfo = new SerializationHelper();
SerializationHelper.GenericDataPreSerializatonAction(this, srinfo);
}
info.AddValue(SerializationNoLabel, SerializationNo);
info.AddValue(StateLabel, (int)this.State);
info.AddValue(InEditLabel, lInEdit);
info.AddValue(HasOriginalValuesLabel, lOriginalValues != null);
for(int i = 0; i < lProperties.Count; i++)
info.AddValue(lProperties[i].PropertyName, lValues[i]);
if(lOriginalValues != null)
{
for(int i = 0; i < lProperties.Count; i++)
if(!lProperties[i].PropertyType.IsByRef)
info.AddValue(OriginalValuesSerializationIdentifier+lProperties[i].PropertyName, lOriginalValues[i]);
}
if(lIntermediarValues != null)
{
for(int i = 0; i < lProperties.Count; i++)
if(!lProperties[i].PropertyType.IsByRef)
info.AddValue(IntermediarValuesSerializationIdentifier+lProperties[i].PropertyName, lIntermediarValues[i]);
}
if(srinfo != null)
{
srinfo.ClearSerialization = true;
SerializationHelper.GenericDataPreSerializatonAction(this, srinfo);
}
}
#endregion
#region IXmlSerializable Members
public void ReadXml(XmlReader reader)
{
this.SuppressEvents = true;
this.lState = GenericDataState.Unchanged;
if(reader.NodeType == XmlNodeType.None)
reader.Read();
// if(reader.IsStartElement(this.GetType().ToString()))
// {
reader.Read();//read stat
this.lState = (GenericDataState)int.Parse(reader.GetAttribute(StateLabel));
this.lInEdit = reader.GetAttribute(InEditLabel).Equals("1");
bool hasOriginalValues = reader.GetAttribute(HasOriginalValuesLabel).Equals("1");
reader.Read();// and move next
while(reader.IsStartElement())
{
if (lProperties.Contains(reader.Name))
{
int PropPos = lProperties.IndexOf(reader.Name);
lProperties[PropPos].ReadXml(reader, this, hasOriginalValues, InEdit);
}
else
reader.ReadString();
//read the end element
reader.Read();
}
// }
this.SuppressEvents = false;
// reader.Read();
}
public void WriteXml(XmlWriter writer)
{
SerializationHelper srinfo = null;
if(!InSerialization)
{
srinfo = new SerializationHelper();
SerializationHelper.GenericDataPreSerializatonAction(this, srinfo);
}
// writer.WriteStartElement(this.GetType().ToString());
writer.WriteStartElement(GeneralStateRegion);
writer.WriteAttributeString(SerializationNoLabel,SerializationNo.ToString());
writer.WriteAttributeString(StateLabel, ((int)this.State).ToString());
writer.WriteAttributeString(InEditLabel, lInEdit == true?"1":"0");
writer.WriteAttributeString(HasOriginalValuesLabel, lOriginalValues != null?"1":"0");
writer.WriteEndElement();
for(int i = 0; i < lProperties.Count; i++)
lProperties[i].WriteXml(writer, this, i, lOriginalValues != null, InEdit);
if(srinfo != null)
{
srinfo.ClearSerialization = true;
SerializationHelper.GenericDataPreSerializatonAction(this, srinfo);
}
// writer.WriteEndElement();
}
public System.Xml.Schema.XmlSchema GetSchema()
{
// TODO: Add GenericData.GetSchema implementation
return null;
}
#endregion
#endregion
#region IDisposable Members
public void Dispose()
{
lValues = null;
lOriginalValues = null;
lIntermediarValues = null;
lProperties = null;
lParent = null;
PropertyModified = null;
}
#endregion
#region IGenericDataParent Members
public void GenericDataChildModified(DataHolder.Containers.GenericData ge, DataHolder.Containers.GEChangeEventArgs args)
{
for(int i =0; i < lProperties.Count; i++)
if(lProperties[i] is Property.TypedProperty
&& this[i] == ge)
{
if(lParent!=null)
lParent.GenericDataChildModified(this, new GEChangeEventArgs( lProperties[i], GEChangeEventArgs.ChangeEventType.FieldChange));
break;
}
}
public void GenericDataCollectionModified(GenericDataCollection gecoll, GECollectionChangeEventArgs args)
{
// Do nothing this is just for compatibility
}
public ParentActions.IGenericDataParent Parent
{
get
{
return lParent;
}
set
{
lParent = value;
}
}
#endregion
#region Generic Data Property Container
//this is the class that keeps all the cached properties
private static Property.PropertyCollectionCache tcollection = null;
public static Property.PropertyCollectionCache TCollection
{
get
{
if(tcollection == null)
throw new Exception("Generic Data Cache not intialized. Please call InitCache");
return tcollection;
}
}
public static void InitCache(Property.PropertyCollectionCache pcache)
{
if(tcollection != null)
throw new Exception("Generic Data Cache allready initlizaized");
tcollection = pcache;
}
#endregion
#region ITypedList Members
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
Property.PropertyCollection pcol = GenericData.TCollection.GetProperties(this);
PropertyDescriptor [] pdesccollection = new PropertyDescriptor[pcol.Count];
for(int i = 0; i < pcol.Count; i++)
pdesccollection[i] = new GenericDataPropertyDescriptor(pcol, pcol[i].PropertyName,null);
return new PropertyDescriptorCollection(pdesccollection);
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
return typeof(GenericDataCollectionView).Name;
}
#endregion
#region UtilFunctions
public bool IsChanged(string PropertyName)
{
return IsChanged(this.Properties.IndexOf(PropertyName));
}
public bool IsChanged(int PropertyIndex)
{
Property.Property prop = this.Properties[PropertyIndex] as Property.Property;
if(prop != null)
return prop.Compare(this[PropertyIndex], this[PropertyIndex, GenericDataVersion.Original]) != 0;
else
return true;
}
public bool IsNull(int Index)
{
return this[Index] == DBNull.Value;
}
public bool IsNull(string PropName)
{
return this[PropName] == DBNull.Value;
}
public bool IsNotNull(params string[] args)
{
if (args == null)
return true;
for (int k = 0; k < args.Length; k++)
if (!IsNull(args[k]))
return false;
return true;
}
public data GetValue<data>(int index, data NullValue)
{
if (IsNull(index))
return NullValue;
else
return (data)this[index];
}
public void SetValue<data>(int index, data newvalue, data NullValue)
{
if (newvalue == null || newvalue.Equals(NullValue))
this[index] = DBNull.Value;
else
this[index] = newvalue;
}
public GenericData Clone()
{
GenericData clone = (GenericData)Activator.CreateInstance(this.GetType());
clone.SuppressEvents = true;
for(int cp=0;cp < this.Properties.Count; cp++)
{
if(this.Properties[cp] is DataHolder.Containers.Property.Property)
clone[cp] = this[cp];
else if(this.Properties[cp] is DataHolder.Containers.Property.TypedProperty)
{
if(this.Properties[cp].PropertyType.IsSubclassOf(typeof(GenericData)))
clone[cp] = ((GenericData)this[cp]).Clone();
else if(this.Properties[cp].PropertyType.IsSubclassOf(typeof(GenericDataCollection)))
clone[cp] = ((GenericDataCollection)this[cp]).Clone();
}
clone.lState = this.State;
}
clone.SuppressEvents = false;
return clone;
}
#endregion
}
}
|