diff --git a/src/Artemis.Core/Attributes/DataModelProperty.cs b/src/Artemis.Core/Attributes/DataModelProperty.cs deleted file mode 100644 index 2135665d0..000000000 --- a/src/Artemis.Core/Attributes/DataModelProperty.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Artemis.Core.Attributes -{ - public class DataModelPropertyAttribute : Attribute - { - public string DisplayName { get; set; } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Models/DataModelDescription.cs b/src/Artemis.Core/Models/DataModelDescription.cs deleted file mode 100644 index c7d950777..000000000 --- a/src/Artemis.Core/Models/DataModelDescription.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Artemis.Core.Models -{ - public class DataModelDescription - { - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/DataModels/Attributes/DataModelIgnoreAttribute.cs b/src/Artemis.Core/Plugins/Abstract/DataModels/Attributes/DataModelIgnoreAttribute.cs new file mode 100644 index 000000000..0dd67b97a --- /dev/null +++ b/src/Artemis.Core/Plugins/Abstract/DataModels/Attributes/DataModelIgnoreAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Artemis.Core.Plugins.Abstract.DataModels.Attributes +{ + public class DataModelIgnoreAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/DataModels/DataModel.cs b/src/Artemis.Core/Plugins/Abstract/DataModels/DataModel.cs index f96b551da..7e72eeaec 100644 --- a/src/Artemis.Core/Plugins/Abstract/DataModels/DataModel.cs +++ b/src/Artemis.Core/Plugins/Abstract/DataModels/DataModel.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Artemis.Core.Exceptions; -using Artemis.Core.Plugins.Abstract.DataModels.Attributes; -using Artemis.Core.Plugins.Exceptions; +using Artemis.Core.Plugins.Abstract.DataModels.Attributes; using Artemis.Core.Plugins.Models; -using SkiaSharp; namespace Artemis.Core.Plugins.Abstract.DataModels { @@ -16,54 +10,9 @@ namespace Artemis.Core.Plugins.Abstract.DataModels /// public PluginInfo PluginInfo { get; internal set; } - /// - /// Gets whether this data model is initialized - /// - public bool Initialized { get; private set; } - /// /// Gets the describing this data model /// public DataModelPropertyAttribute DataModelDescription { get; internal set; } - - /// - /// If found on this type, returns the for the provided property name - /// - /// The name of the property on to look for - public DataModelPropertyAttribute GetPropertyAttribute(string propertyName) - { - var propertyInfo = GetType().GetProperty(propertyName); - if (propertyInfo == null) - return null; - - return (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute)); - } - - internal void Initialize() - { - // Doubt this will happen but let's make sure - if (Initialized) - throw new ArtemisCoreException("Data model already initialized, wut"); - - foreach (var propertyInfo in GetType().GetProperties()) - { - var dataModelPropertyAttribute = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute)); - if (dataModelPropertyAttribute == null || !typeof(DataModel).IsAssignableFrom(propertyInfo.PropertyType)) - continue; - - // If the property is a nested datamodel create an instance and initialize it - var instance = (DataModel) Activator.CreateInstance(propertyInfo.PropertyType, true); - if (instance == null) - throw new ArtemisCoreException($"Failed to create instance of child datamodel at {propertyInfo.Name}"); - - instance.PluginInfo = PluginInfo; - instance.DataModelDescription = dataModelPropertyAttribute; - instance.Initialize(); - - propertyInfo.SetValue(this, instance); - } - - Initialized = true; - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/DataModelService.cs b/src/Artemis.Core/Services/DataModelService.cs index 7719b8005..e5cdd5273 100644 --- a/src/Artemis.Core/Services/DataModelService.cs +++ b/src/Artemis.Core/Services/DataModelService.cs @@ -61,37 +61,26 @@ namespace Artemis.Core.Services } } - public DataModelDescription GetMainDataModelDescription() - { - var dataModelDescription = new DataModelDescription(); - - return dataModelDescription; - } - private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) { if (e.PluginInfo.Instance is Module module && module.InternalExpandsMainDataModel) { - if (!module.InternalDataModel.Initialized) + if (module.InternalDataModel.DataModelDescription == null) { module.InternalDataModel.DataModelDescription = module.InternalGetDataModelDescription(); if (module.InternalDataModel.DataModelDescription == null) throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null"); - - module.InternalDataModel.Initialize(); } _dataModelExpansions.Add(module.InternalDataModel); } else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion) { - if (!dataModelExpansion.InternalDataModel.Initialized) + if (dataModelExpansion.InternalDataModel.DataModelDescription == null) { dataModelExpansion.InternalDataModel.DataModelDescription = dataModelExpansion.GetDataModelDescription(); if (dataModelExpansion.InternalDataModel.DataModelDescription == null) throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null"); - - dataModelExpansion.InternalDataModel.Initialize(); } _dataModelExpansions.Add(dataModelExpansion.InternalDataModel); diff --git a/src/Artemis.Core/Services/Interfaces/IDataModelService.cs b/src/Artemis.Core/Services/Interfaces/IDataModelService.cs index 91052248f..c8a1089e0 100644 --- a/src/Artemis.Core/Services/Interfaces/IDataModelService.cs +++ b/src/Artemis.Core/Services/Interfaces/IDataModelService.cs @@ -1,10 +1,13 @@ -using Artemis.Core.Models; +using System.Collections.ObjectModel; +using Artemis.Core.Models; using Artemis.Core.Plugins.Abstract.DataModels; namespace Artemis.Core.Services.Interfaces { public interface IDataModelService : IArtemisService { + ReadOnlyCollection DataModelExpansions { get; } + /// /// Add an expansion to the datamodel to be available for use after the next update /// @@ -16,11 +19,5 @@ namespace Artemis.Core.Services.Interfaces /// /// void RemoveExpansion(DataModel baseDataModelExpansion); - - /// - /// Generates a data model description for the main datamodel including all it's expansions - /// - /// The generated data model description - DataModelDescription GetMainDataModelDescription(); } } \ No newline at end of file diff --git a/src/Artemis.UI/DataModelVisualization/DataModelGroupViewModel.cs b/src/Artemis.UI/DataModelVisualization/DataModelGroupViewModel.cs new file mode 100644 index 000000000..e313194bc --- /dev/null +++ b/src/Artemis.UI/DataModelVisualization/DataModelGroupViewModel.cs @@ -0,0 +1,11 @@ +using Artemis.Core.Plugins.Abstract.DataModels.Attributes; +using Stylet; + +namespace Artemis.UI.DataModelVisualization +{ + public abstract class DataModelVisualizationViewModel : PropertyChangedBase + { + public DataModelPropertyAttribute PropertyDescription { get; protected set; } + public DataModelViewModel Parent { get; protected set; } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/DataModelVisualization/DataModelPropertyViewModel.cs b/src/Artemis.UI/DataModelVisualization/DataModelPropertyViewModel.cs new file mode 100644 index 000000000..8ab70d14c --- /dev/null +++ b/src/Artemis.UI/DataModelVisualization/DataModelPropertyViewModel.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using Artemis.Core.Plugins.Abstract.DataModels.Attributes; +using FastMember; + +namespace Artemis.UI.DataModelVisualization +{ + public class DataModelPropertyViewModel : DataModelVisualizationViewModel + { + private readonly ObjectAccessor _accessor; + + public DataModelPropertyViewModel(PropertyInfo propertyInfo, DataModelPropertyAttribute propertyDescription, DataModelViewModel parent) + { + _accessor = ObjectAccessor.Create(parent.Model); + + PropertyInfo = propertyInfo; + Parent = parent; + PropertyDescription = propertyDescription; + } + + public PropertyInfo PropertyInfo { get; } + public object Value => _accessor[PropertyInfo.Name]; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/DataModelVisualization/DataModelViewModel.cs b/src/Artemis.UI/DataModelVisualization/DataModelViewModel.cs index cc514063a..c38c4fd73 100644 --- a/src/Artemis.UI/DataModelVisualization/DataModelViewModel.cs +++ b/src/Artemis.UI/DataModelVisualization/DataModelViewModel.cs @@ -1,54 +1,57 @@ using System; -using System.Linq; -using Artemis.Core.Attributes; -using Artemis.Core.Plugins.Abstract.DataModels; -using Artemis.UI.Exceptions; +using Artemis.Core.Plugins.Abstract.DataModels.Attributes; +using Humanizer; using Stylet; namespace Artemis.UI.DataModelVisualization { - public class DataModelViewModel : PropertyChangedBase + public class DataModelViewModel : DataModelVisualizationViewModel { - public DataModelViewModel(DataModel dataModel) + public DataModelViewModel() { - if (!DataModel.Initialized) - throw new ArtemisUIException("Cannot create view model for data model that is not yet initialized"); - - DataModel = dataModel; + Children = new BindableCollection(); } - public DataModelViewModel(DataModel parent, DataModel dataModel) + public DataModelViewModel(object model, DataModelPropertyAttribute propertyDescription, DataModelViewModel parent) { - if (!DataModel.Initialized) - throw new ArtemisUIException("Cannot create view model for data model that is not yet initialized"); - + Model = model; + PropertyDescription = propertyDescription; Parent = parent; - DataModel = dataModel; + Children = new BindableCollection(); + + PopulateProperties(); } - public DataModel DataModel { get; } - public DataModel Parent { get; set; } + public object Model { get; } + public BindableCollection Children { get; set; } - - private void PopulateProperties() + public void PopulateProperties() { - foreach (var propertyInfo in DataModel.GetType().GetProperties()) + Children.Clear(); + foreach (var propertyInfo in Model.GetType().GetProperties()) { - var dataModelPropertyAttribute = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute)); - if (dataModelPropertyAttribute == null) + // Skip properties decorated with DataModelIgnore + if (Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute))) continue; - // For child data models create another data model view model - if (typeof(DataModel).IsAssignableFrom(propertyInfo.PropertyType)) + var dataModelPropertyAttribute = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(DataModelPropertyAttribute)); + // If no DataModelProperty attribute was provided, pull one out of our ass + if (dataModelPropertyAttribute == null) + dataModelPropertyAttribute = new DataModelPropertyAttribute {Name = propertyInfo.Name.Humanize()}; + + // For value types create a child view model if the value type is not null + if (propertyInfo.PropertyType.IsValueType) { + var value = propertyInfo.GetValue(Model); + if (value == null) + continue; + + Children.Add(new DataModelViewModel(value, dataModelPropertyAttribute, this)); } - // For primitives, create a property view model + // For primitives, create a property view model, it may be null that is fine else if (propertyInfo.PropertyType.IsPrimitive) { - } - // For anything else check if it has any child primitives and if so create a property container view model - else if (propertyInfo.PropertyType.GetProperties().Any(p => p.PropertyType.IsPrimitive)) - { + Children.Add(new DataModelPropertyViewModel(propertyInfo, dataModelPropertyAttribute, this)); } } } diff --git a/src/Artemis.UI/Services/DataModelVisualizationService.cs b/src/Artemis.UI/Services/DataModelVisualizationService.cs new file mode 100644 index 000000000..703a98505 --- /dev/null +++ b/src/Artemis.UI/Services/DataModelVisualizationService.cs @@ -0,0 +1,30 @@ +using Artemis.Core.Services.Interfaces; +using Artemis.UI.DataModelVisualization; +using Artemis.UI.Services.Interfaces; + +namespace Artemis.UI.Services +{ + public class DataModelVisualizationService : IDataModelVisualizationService + { + private readonly IDataModelService _dataModelService; + + public DataModelVisualizationService(IDataModelService dataModelService) + { + _dataModelService = dataModelService; + } + + public DataModelViewModel GetMainDataModelVisualization() + { + var viewModel = new DataModelViewModel(); + foreach (var dataModelExpansion in _dataModelService.DataModelExpansions) + viewModel.Children.Add(new DataModelViewModel(dataModelExpansion, dataModelExpansion.DataModelDescription, viewModel)); + + return viewModel; + } + } + + public interface IDataModelVisualizationService : IArtemisUIService + { + public DataModelViewModel GetMainDataModelVisualization(); + } +} \ No newline at end of file