using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Bulasoft.Common.Elements;
using Bulasoft.Common.Serialization;
using Bulasoft.Common.Utils;
namespace Bulasoft.Common.Elements
{
[Flags]
public enum ElementState
{
New = 0x01,
ThisModified = 0x02,
ChildrenModified = 0x04,
Changed = New | ThisModified | ChildrenModified,
MaskChanges = New | ThisModified | ChildrenModified,
Public = 0x00,
ElementReadOnly = 0x10,
ElementAndChildReadOnly = 0x20,
Private = 0x40,
MaskAccess = Public | ElementReadOnly | ElementAndChildReadOnly | Private
}
public enum ElementAccess
{
Public,
ElementReadOnly,
ElementAndChildrenReadOnly,
Private
}
[ToolboxItem(false)]
public class Element : DefaultElement, IElement, IEnumerable, IComparer<IElement>, IComponent, ISite, ICustomTypeDescriptor, IComparable<IElement>, IComparable, INotifyPropertyChanged
{
public const string AuthorName = "Author";
public const string ContainerName = "Container";
public const string DeletedName = "Deleted";
public const string DescriptionName = "Description";
public const string ReferenceName = "Ref";
public const string ElementAccessName = "ElementAccess";
protected internal virtual void AddInnerElement(IElement element)
{
element.Container = this;
element.State = element.State & ~ElementState.MaskAccess;
}
public virtual IElement Find(Guid id)
{
return containerElements.Find(delegate(IElement elem) { return elem.ID == id; });
}
private string _author;
[Serialization(AuthorName)]
[Category("Design"), ReadOnly(true), Description("Author name")]
public string Author
{
get { return _author; }
set
{
if (value != _author)
{
LogChange(AuthorName, _author, value);
_author = value;
NotifyPropertyChange(AuthorName);
}
}
}
[Browsable(false)]
IElement IElement.Container
{
get { return base.Container; }
set
{
if (Container != value)
{
ValidateNewContainer(value);
if (Container != null)
Container.RemoveElement(this);
if (value != null)
value.AddElement(this);
base.Container = value;
SetElementSpace(GetContainer<ElementSpace>());
}
}
}
[Browsable(false)]
public new Element Container
{
get { return base.Container as Element; }
}
public virtual void Validate(Logger log) { }
public virtual bool CanDelete(out Logger log)
{
log = new Logger();
return true;
}
protected virtual void ValidateNewContainer(IElement container)
{ }
[Browsable(false)]
public virtual IEnumerable ImplicitList
{
get { return null; }
}
[Serialization(DeletedName)]
[Category("Design"), DefaultValue(false), Description("Indicates that object is deleted")]
[ReadOnly(true)]
public override bool IsDeleted
{
get { return (ElementSpace != null) && ElementSpace.IsDeletedElement(this); }
set
{
bool oldValue = IsDeleted;
if (value != oldValue)
{
if (ElementSpace == null)
{
if (value) return;
throw new Exception("Unsupported Operation: ElementSpace required");
}
LogChange(DeletedName, oldValue, value);
if (value)
ElementSpace.DeleteElement(this);
else
ElementSpace.UndeleteElement(this);
NotifyPropertyChange(DeletedName);
}
}
}
private string _description;
[Serialization(DescriptionName)]
[Category("Design")]
[Description("Description of the object")]
public virtual string Description
{
get { return _description; }
set
{
if (_description != value)
{
LogChange(DescriptionName, _description, value);
_description = value;
NotifyPropertyChange(DescriptionName);
}
}
}
[Browsable(false)]
public virtual string QualifiedName
{
get
{
if (this is ElementSpace)
return Name;
else
{
StringBuilder sb = new StringBuilder();
IElement el = this;
while ((el != null) && !(el is ElementSpace))
{
sb.Insert(0, "." + el.Name);
el = el.Container;
}
sb.Remove(0, 1);
return sb.ToString();
}
}
}
[Serialization()]
[Browsable(false)]
[Category("Design")]
[DefaultValue(ElementAccess.Public)]
public ElementAccess ElementAccess
{
get
{
switch (State & ElementState.MaskAccess)
{
case ElementState.Private:
return ElementAccess.Private;
case ElementState.ElementAndChildReadOnly:
return ElementAccess.ElementAndChildrenReadOnly;
case ElementState.ElementReadOnly:
return ElementAccess.ElementReadOnly;
default:
return ElementAccess.Public;
}
}
set
{
if (ElementAccess != value)
{
LogChange(ElementAccessName, ElementAccess, value);
switch (value)
{
case ElementAccess.Public:
State = (State & ~ElementState.MaskAccess) | ElementState.Public;
break;
case ElementAccess.ElementReadOnly:
State = (State & ~ElementState.MaskAccess) | ElementState.ElementReadOnly;
break;
case ElementAccess.ElementAndChildrenReadOnly:
State = (State & ~ElementState.MaskAccess) | ElementState.ElementAndChildReadOnly;
break;
case ElementAccess.Private:
State = (State & ~ElementState.MaskAccess) | ElementState.Private;
break;
}
NotifyPropertyChange(ElementAccessName);
}
}
}
[Browsable(false)]
public bool IsPrivate
{
get { return ElementAccess == ElementAccess.Private; }
}
private ElementSpace _elementSpace;
[Browsable(false)]
public ElementSpace ElementSpace
{
get { return _elementSpace; }
}
public TContainer GetContainer<TContainer>() where TContainer : Element
{
IElement container = this;
while (container != null)
{
TContainer result = container as TContainer;
if (result != null)
return result;
else
container = container.Container;
}
return null;
}
[Browsable(false)]
public bool IsToBeDeleted
{
get { return (IsDeleted || ((Container != null) &&Container.IsToBeDeleted)); }
}
[Category("Design"), DisplayName("ID"), Description("Object identification")]
public virtual string QualifiedID
{
get
{
if (ID != null)
return ID.ToString();
else
return Name;
}
}
[Serialization(IDName)]
[Browsable(false)]
public override Guid? ID
{
get { return base.ID; }
set
{
if (ID != value)
{
LogChange(IDName, ID, value);
if (ElementSpace != null)
{
if (ID != null)
ElementSpace.UnregisterElement(this);
base.ID = value;
if (ID != null)
ElementSpace.RegisterElement(this);
}
else
base.ID = value;
NotifyPropertyChange(IDName);
}
}
}
[Browsable(false)]
public bool IsNew
{
get { return (State & ElementState.New) != 0; }
}
public string GetSerializationName(PropertyInfo propInfo)
{
string SerialName = propInfo.Name;
SerializationAttribute Attr = Attribute.GetCustomAttribute(propInfo, typeof(SerializationAttribute)) as SerializationAttribute;
if ((Attr != null) && (!string.IsNullOrEmpty(Attr.Name)))
SerialName = Attr.Name;
return SerialName;
}
protected internal void LogChange(object oldValue, object newValue)
{
if (!TrackChanges())
return;
StackTrace st = new StackTrace();
StackFrame sf = st.GetFrame(1);
MethodBase mb = sf.GetMethod();
string MethodName = mb.Name;
if (MethodName.StartsWith("set_"))
{
string PropertyName = MethodName.Substring(4);
PropertyInfo propInfo = GetType().GetProperty(PropertyName);
LogChange(GetSerializationName(propInfo), oldValue, newValue);
}
}
protected internal void LogChange(string propertyName, object key, object orgValue, object newValue)
{
if (key == null)
LogChange(propertyName, orgValue, newValue);
else
LogChange(string.Format("{0}-{1}", propertyName, key), orgValue, newValue);
}
public event EventHandler<ElementArgs> OnElemenChanged;
protected override void LogChange(string propertyName, object orgValue, object newValue)
{
if (OnElemenChanged != null)
OnElemenChanged(this, new ElementArgs(this, propertyName));
base.LogChange(propertyName, orgValue, newValue);
}
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
[Serialization(ElementName, SerializationSettings.SerializeAsAttribute)]
[Category("Design")]
public override string Name
{
get { return base.Name; }
set
{
if (!String.Equals(Name, value))
{
ValidateName(value);
LogChange(ElementName, Name, value);
base.Name = value;
NotifyPropertyChange(ElementName);
NameChanged();
}
}
}
protected virtual void NameChanged()
{ }
protected internal void Register()
{
if (ID != null) ElementSpace.RegisterElement(this);
foreach (Element element in this)
element.Register();
}
protected void SetElementSpace(ElementSpace value)
{
if (ElementSpace != value)
{
if ((ID != null) && (ElementSpace != null))
ElementSpace.UnregisterElement(this);
_elementSpace = value;
if ((ID != null) && (value != null))
value.RegisterElement(this);
foreach (Element element in this)
element.SetElementSpace(value);
}
}
protected override bool TrackChanges()
{
if (ElementSpace != null)
return ElementSpace.ChangesTracked;
else
return base.TrackChanges();
}
public override void AcceptChanges()
{
if (OnElemenChanged != null)
OnElemenChanged(this, null);
State &= ~ElementState.MaskChanges;
foreach (Element element in this)
element.AcceptChanges();
base.AcceptChanges();
}
protected internal void Unregister()
{
if (ID != null)
ElementSpace.UnregisterElement(this);
foreach (Element element in this)
element.Unregister();
}
protected override void MarkModified(ElementState addedFlags)
{
if ((base.Container != null) && ((base.Container.State & ElementState.ChildrenModified) == 0))
{
if (OnElemenChanged != null)
OnElemenChanged(this, null);
if (base.Container is Element)
((Element) base.Container).MarkModified(ElementState.ChildrenModified);
}
State |= addedFlags;
}
protected virtual void ValidateName(string value)
{
if (FixedName)
throw new Exception("Cannot change a fix name");
if (string.IsNullOrEmpty(value))
throw new Exception("Empty name is not valid");
if ((Container != null) &&
ReflectionHelper.ImplementsGenericInterface(Container.GetType(), typeof(ICollection<>)))
foreach (Element element in Container)
{
if ((element != this) && (element.Name == value))
throw new Exception(string.Format("Name {0} alreday used", element.Name));
}
}
public int Compare(IElement x, IElement y)
{
string xQualifiedName = null;
string yQualifiedName = null;
Element xElement = x as Element;
if (xElement != null)
xQualifiedName = xElement.QualifiedName;
Element yElement = y as Element;
if (yElement != null)
yQualifiedName = yElement.QualifiedName;
return string.Compare(xQualifiedName, yQualifiedName, true);
}
public virtual void Sort()
{
containerElements.Sort(this);
foreach (Element element in this)
element.Sort();
}
#region IComponent Members
public event EventHandler Disposed;
[Browsable(false)]
public ISite Site
{
get
{
return this;
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
if (Container != null)
Container.RemoveElement(this);
foreach (Element element in this)
element.Dispose();
if (Disposed != null)
Disposed(this, EventArgs.Empty);
}
}
}
#endregion
#region ISite Members
[Browsable(false)]
public IComponent Component
{
get { return this; }
}
[Browsable(false)]
IContainer ISite.Container
{
get { return null; }
}
[Browsable(false)]
public bool DesignMode
{
get { return true; }
}
#endregion
#region IServiceProvider Members
public object GetService(Type serviceType)
{
if (serviceType == typeof(ISite))
return this;
else
return null;
}
#endregion
#region ICustomTypeDescriptor Members
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
string ICustomTypeDescriptor.GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return Filter(TypeDescriptor.GetProperties(this, attributes, true));
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return Filter(TypeDescriptor.GetProperties(this, true));
}
protected virtual PropertyDescriptorCollection Filter(PropertyDescriptorCollection original)
{
return original;
}
protected virtual PropertyDescriptorCollection Filter(PropertyDescriptorCollection original, List<PropertyDescriptor> forbiddenProperties)
{
if ((forbiddenProperties == null) || (forbiddenProperties.Count == 0))
return original;
else
{
List<PropertyDescriptor> result = new List<PropertyDescriptor>();
foreach (PropertyDescriptor pd in original)
{
if (forbiddenProperties.IndexOf(pd) == -1)
result.Add(pd);
}
return new PropertyDescriptorCollection(result.ToArray());
}
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion
#region IComparable<IElement> Members
public int CompareTo(IElement other)
{
return Compare(this, other);
}
#endregion
#region IComparable Members
public int CompareTo(object obj)
{
return CompareTo(obj as IElement);
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}