// Copyright (C) Stichting Deltares 2021. All rights reserved.
//
// This file is part of Riskeer.
//
// Riskeer is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Core.Common.Gui.Attributes;
using Core.Common.Gui.Forms.PropertyGridView;
namespace Core.Common.Gui.PropertyBag
{
///
/// Defines a custom type descriptor for an object to be used as view-model for .
/// It processes the special attributes defined in Core.Common.Gui.Attributes
/// to dynamically affect property order or adding/removing .
///
/// This class makes sure the following special attributes on properties are processed:
///
///
///
///
///
///
/// Worth mentioning is the fact that, when specified both, the
/// overrules the .
///
public class DynamicPropertyBag : ICustomTypeDescriptor
{
///
/// Creates a new instance of , wrapping another
/// object and exposing properties for that object.
///
/// The object to be wrapped.
/// Thrown when
/// is null.
public DynamicPropertyBag(object propertyObject)
{
if (propertyObject == null)
{
throw new ArgumentNullException(nameof(propertyObject));
}
var properties = new HashSet();
foreach (PropertyInfo propertyInfo in propertyObject.GetType().GetProperties()
.OrderBy(x => x.MetadataToken))
{
properties.Add(new PropertySpec(propertyInfo));
}
Properties = properties;
WrappedObject = propertyObject;
}
///
/// Gets the set of properties contained within this .
///
public IEnumerable Properties { get; }
///
/// Gets the object wrapped inside this .
///
public object WrappedObject { get; }
public override string ToString()
{
return WrappedObject.ToString();
}
#region ICustomTypeDescriptor explicit interface definitions
#region Implementations delegated to System.ComponentModel.TypeDescriptor
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
#endregion
public PropertyDescriptor GetDefaultProperty()
{
return Properties.Any() ? new PropertySpecDescriptor(Properties.First(), WrappedObject) : null;
}
public PropertyDescriptorCollection GetProperties()
{
return GetProperties(new Attribute[0]);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
IEnumerable propertyDescriptorsToReturn = Properties.Select(p => new PropertySpecDescriptor(p, WrappedObject))
.Where(t => ShouldDescriptorBeReturned(t, attributes));
PropertyDescriptor[] propertySpecDescriptors = OrderPropertyDescriptors(propertyDescriptorsToReturn);
return new PropertyDescriptorCollection(propertySpecDescriptors);
}
private PropertyDescriptor[] OrderPropertyDescriptors(IEnumerable propertyDescriptorsToReturn)
{
var unorderedProperties = new List();
var propertiesWithOrdering = new List>();
foreach (PropertyDescriptor pd in propertyDescriptorsToReturn)
{
PropertyOrderAttribute propertyOrderAttribute = pd.Attributes.OfType().FirstOrDefault();
if (propertyOrderAttribute != null)
{
propertiesWithOrdering.Add(Tuple.Create(propertyOrderAttribute.Order, pd));
continue;
}
DynamicPropertyOrderAttribute dynamicPropertyOrderAttribute = pd.Attributes.OfType().FirstOrDefault();
if (dynamicPropertyOrderAttribute != null)
{
propertiesWithOrdering.Add(Tuple.Create(DynamicPropertyOrderAttribute.PropertyOrder(WrappedObject, pd.Name), pd));
continue;
}
unorderedProperties.Add(pd);
}
IEnumerable orderedProperties = propertiesWithOrdering.OrderBy(p => p.Item1).Select(p => p.Item2);
return orderedProperties.Concat(unorderedProperties).ToArray();
}
private static bool ShouldDescriptorBeReturned(PropertyDescriptor propertySpecDescriptor, IEnumerable attributesFilter)
{
BrowsableAttribute browsableAttribute = attributesFilter.OfType().FirstOrDefault();
return browsableAttribute == null || propertySpecDescriptor.IsBrowsable == browsableAttribute.Browsable;
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return WrappedObject;
}
#endregion
}
}