From 1de6fefc2a121f7b5b2c06543cb599d4a666941c Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Wed, 9 Sep 2020 23:01:36 +0200 Subject: [PATCH] Display conditions - Implemented IDisposable Display conditions - Listen to registration add/remove WIP Data bindings - Implemented IDisposable Data bindings - Listen to registration add/remove --- .../Abstract/DisplayConditionPart.cs | 23 ++- .../Conditions/DisplayConditionGroup.cs | 21 +++ .../Conditions/DisplayConditionList.cs | 68 +++++++- .../Conditions/DisplayConditionPredicate.cs | 40 +++++ .../Profile/DataBindings/DataBinding.cs | 98 ++++++++--- .../DataBindings/DataBindingModifier.cs | 154 +++++++++++++----- .../Profile/DataBindings/IDataBinding.cs | 16 +- .../DataBindings/IDataBindingModifier.cs | 6 +- .../Abstract/DataBindingModifierType.cs | 34 ---- .../Profile/LayerProperties/ILayerProperty.cs | 5 +- .../Profile/LayerProperties/LayerProperty.cs | 62 ++++++- .../Models/Profile/LayerPropertyGroup.cs | 18 +- src/Artemis.Core/Models/Profile/Profile.cs | 4 +- .../Models/Profile/RenderProfileElement.cs | 17 ++ .../Services/Storage/ProfileService.cs | 101 +----------- .../PropertyGroups/ColorBrushProperties.cs | 15 +- .../RadialGradientProperties.cs | 6 +- 17 files changed, 461 insertions(+), 227 deletions(-) diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs index 2669afc17..72ca6a7c4 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.Abstract; @@ -7,7 +8,7 @@ namespace Artemis.Core /// /// An abstract class for display condition parts /// - public abstract class DisplayConditionPart + public abstract class DisplayConditionPart : IDisposable { private readonly List _children = new List(); @@ -62,5 +63,23 @@ namespace Artemis.Core internal abstract void ApplyToEntity(); internal abstract DisplayConditionPartEntity GetEntity(); + + #region IDisposable + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs index e68dd9e57..cc4cc7e49 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs @@ -11,6 +11,8 @@ namespace Artemis.Core /// public class DisplayConditionGroup : DisplayConditionPart { + private bool _disposed; + /// /// Creates a new instance of the class /// @@ -55,6 +57,9 @@ namespace Artemis.Core /// public override bool Evaluate() { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionGroup"); + // Empty groups are always true if (Children.Count == 0) return true; @@ -80,6 +85,9 @@ namespace Artemis.Core /// public override bool EvaluateObject(object target) { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionGroup"); + // Empty groups are always true if (Children.Count == 0) return true; @@ -111,6 +119,19 @@ namespace Artemis.Core { return Entity; } + + #region IDisposable + + protected override void Dispose(bool disposing) + { + _disposed = true; + foreach (var child in Children) + child.Dispose(); + + base.Dispose(disposing); + } + + #endregion } public enum BooleanOperator diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs index bd9c54b76..155ae3489 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs @@ -10,6 +10,8 @@ namespace Artemis.Core { public class DisplayConditionList : DisplayConditionPart { + private bool _disposed; + public DisplayConditionList(DisplayConditionPart parent) { Parent = parent; @@ -37,6 +39,9 @@ namespace Artemis.Core public override bool Evaluate() { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionList"); + if (CompiledListAccessor == null) return false; @@ -45,6 +50,9 @@ namespace Artemis.Core public override bool EvaluateObject(object target) { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionList"); + if (!Children.Any()) return false; if (!(target is IList list)) @@ -63,6 +71,9 @@ namespace Artemis.Core public void UpdateList(DataModel dataModel, string path) { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionList"); + if (dataModel != null && path == null) throw new ArtemisCoreException("If a data model is provided, a path is also required"); if (dataModel == null && path != null) @@ -93,6 +104,9 @@ namespace Artemis.Core public void CreateExpression() { + if (_disposed) + throw new ObjectDisposedException("DisplayConditionList"); + var parameter = Expression.Parameter(typeof(object), "listDataModel"); var accessor = ListPropertyPath.Split('.').Aggregate( Expression.Convert(parameter, ListDataModel.GetType()), @@ -101,12 +115,15 @@ namespace Artemis.Core var lambda = Expression.Lambda>(accessor, parameter); CompiledListAccessor = lambda.Compile(); } - + internal override void ApplyToEntity() { // Target list - Entity.ListDataModelGuid = ListDataModel?.PluginInfo?.Guid; - Entity.ListPropertyPath = ListPropertyPath; + if (ListDataModel != null) + { + Entity.ListDataModelGuid = ListDataModel.PluginInfo.Guid; + Entity.ListPropertyPath = ListPropertyPath; + } // Operator Entity.ListOperator = (int) ListOperator; @@ -125,6 +142,8 @@ namespace Artemis.Core internal void Initialize() { + DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved; if (Entity.ListDataModelGuid == null) return; @@ -147,6 +166,49 @@ namespace Artemis.Core AddChild(new DisplayConditionGroup(this)); } } + + + #region Event handlers + + private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e) + { + var dataModel = e.Registration.DataModel; + if (dataModel.PluginInfo.Guid == Entity.ListDataModelGuid && dataModel.ContainsPath(Entity.ListPropertyPath)) + { + ListDataModel = dataModel; + ListPropertyPath = Entity.ListPropertyPath; + CreateExpression(); + } + } + + private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) + { + if (ListDataModel != e.Registration.DataModel) + return; + + ListDataModel = null; + CompiledListAccessor = null; + } + + #endregion + + #region IDisposable + + /// + protected override void Dispose(bool disposing) + { + _disposed = true; + + DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; + + foreach (var child in Children) + child.Dispose(); + + base.Dispose(disposing); + } + + #endregion } public enum ListOperator diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs index 70a7a890a..53d70de8a 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs @@ -248,6 +248,9 @@ namespace Artemis.Core internal void Initialize() { + DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved; + // Left side if (Entity.LeftDataModelGuid != null) { @@ -424,5 +427,42 @@ namespace Artemis.Core Expression.Property ); } + + #region Event handlers + + private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e) + { + var dataModel = e.Registration.DataModel; + if (dataModel.PluginInfo.Guid == Entity.LeftDataModelGuid && dataModel.ContainsPath(Entity.LeftPropertyPath)) + UpdateLeftSide(dataModel, Entity.LeftPropertyPath); + if (dataModel.PluginInfo.Guid == Entity.RightDataModelGuid && dataModel.ContainsPath(Entity.RightPropertyPath)) + UpdateRightSide(dataModel, Entity.RightPropertyPath); + } + + private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) + { + if (LeftDataModel == e.Registration.DataModel) + { + CompiledDynamicPredicate = null; + LeftDataModel = null; + } + + if (RightDataModel == e.Registration.DataModel) + { + CompiledDynamicPredicate = null; + RightDataModel = null; + } + } + + #endregion + + /// + protected override void Dispose(bool disposing) + { + DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; + + base.Dispose(disposing); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs index d3f8bd9f3..7e5240820 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBinding.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using Artemis.Core.DataModelExpansions; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.DataBindings; namespace Artemis.Core @@ -17,6 +16,7 @@ namespace Artemis.Core private TProperty _currentValue; private TimeSpan _easingProgress; private TProperty _previousValue; + private bool _disposed; internal DataBinding(DataBindingRegistration dataBindingRegistration) { @@ -25,6 +25,7 @@ namespace Artemis.Core ApplyRegistration(dataBindingRegistration); Save(); + Initialize(); } internal DataBinding(LayerProperty layerProperty, DataBindingEntity entity) @@ -32,6 +33,8 @@ namespace Artemis.Core LayerProperty = layerProperty; Entity = entity; + // Load will add children so be initialized before that + Initialize(); Load(); } @@ -95,6 +98,9 @@ namespace Artemis.Core /// The time in seconds that passed since the last update public void Update(double deltaTime) { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + // Data bindings cannot go back in time like brushes deltaTime = Math.Max(0, deltaTime); @@ -103,11 +109,27 @@ namespace Artemis.Core _easingProgress = EasingTime; } + /// + public void Apply() + { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + + if (Converter == null) + return; + + var value = GetValue(Converter.GetValue()); + Converter.ApplyValue(GetValue(value)); + } + /// /// Adds a modifier to the data binding's collection /// public void AddModifier(DataBindingModifier modifier) { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + if (!_modifiers.Contains(modifier)) { modifier.DataBinding = this; @@ -122,6 +144,9 @@ namespace Artemis.Core /// public void RemoveModifier(DataBindingModifier modifier) { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + if (_modifiers.Contains(modifier)) { modifier.DataBinding = null; @@ -138,6 +163,9 @@ namespace Artemis.Core /// The path pointing to the source inside the data model public void UpdateSource(DataModel dataModel, string path) { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + if (dataModel != null && path == null) throw new ArtemisCoreException("If a data model is provided, a path is also required"); if (dataModel == null && path != null) @@ -161,6 +189,9 @@ namespace Artemis.Core /// public TProperty GetValue(TProperty baseValue) { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + if (CompiledTargetAccessor == null || Converter == null) return baseValue; @@ -198,30 +229,18 @@ namespace Artemis.Core return SourceDataModel?.GetTypeAtPath(SourcePropertyPath); } - /// - public void Apply() + private void Initialize() { - if (Converter == null) - return; + DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved; - var value = GetValue(Converter.GetValue()); - Converter.ApplyValue(GetValue(value)); - } - - /// - public void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService) - { // Source if (Entity.SourceDataModelGuid != null && SourceDataModel == null) { - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.SourceDataModelGuid.Value); + var dataModel = DataModelStore.Get(Entity.SourceDataModelGuid.Value)?.DataModel; if (dataModel != null && dataModel.ContainsPath(Entity.SourcePropertyPath)) UpdateSource(dataModel, Entity.SourcePropertyPath); } - - // Modifiers - foreach (var dataBindingModifier in Modifiers) - dataBindingModifier.Initialize(dataModelService, dataBindingService); } private void ResetEasing(TProperty value) @@ -283,6 +302,8 @@ namespace Artemis.Core /// public void Load() { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); // General var registration = LayerProperty.GetDataBindingRegistration(Entity.TargetProperty); ApplyRegistration(registration); @@ -301,6 +322,9 @@ namespace Artemis.Core /// public void Save() { + if (_disposed) + throw new ObjectDisposedException("DataBinding"); + if (!LayerProperty.Entity.DataBindingEntities.Contains(Entity)) LayerProperty.Entity.DataBindingEntities.Add(Entity); @@ -311,9 +335,12 @@ namespace Artemis.Core Entity.EasingFunction = (int) EasingFunction; // Data model - Entity.SourceDataModelGuid = SourceDataModel?.PluginInfo?.Guid; - Entity.SourcePropertyPath = SourcePropertyPath; - + if (SourceDataModel != null) + { + Entity.SourceDataModelGuid = SourceDataModel.PluginInfo.Guid; + Entity.SourcePropertyPath = SourcePropertyPath; + } + // Modifiers Entity.Modifiers.Clear(); foreach (var dataBindingModifier in Modifiers) @@ -322,6 +349,25 @@ namespace Artemis.Core #endregion + #region Event handlers + + private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e) + { + var dataModel = e.Registration.DataModel; + if (dataModel.PluginInfo.Guid == Entity.SourceDataModelGuid && dataModel.ContainsPath(Entity.SourcePropertyPath)) + UpdateSource(dataModel, Entity.SourcePropertyPath); + } + + private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) + { + if (SourceDataModel != e.Registration.DataModel) + return; + SourceDataModel = null; + CompiledTargetAccessor = null; + } + + #endregion + #region Events /// @@ -335,6 +381,18 @@ namespace Artemis.Core } #endregion + + /// + public void Dispose() + { + _disposed = true; + + DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; + + foreach (var dataBindingModifier in Modifiers) + dataBindingModifier.Dispose(); + } } /// diff --git a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs index 18571fcde..bd25a62cf 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/DataBindingModifier.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Linq.Expressions; using Artemis.Core.DataModelExpansions; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.DataBindings; using Newtonsoft.Json; @@ -12,6 +11,7 @@ namespace Artemis.Core public class DataBindingModifier : IDataBindingModifier { private DataBinding _dataBinding; + private bool _disposed; /// /// Creates a new instance of the class @@ -22,6 +22,7 @@ namespace Artemis.Core ParameterType = parameterType; Entity = new DataBindingModifierEntity(); Save(); + Initialize(); } internal DataBindingModifier(DataBinding dataBinding, DataBindingModifierEntity entity) @@ -29,6 +30,7 @@ namespace Artemis.Core DataBinding = dataBinding; Entity = entity; Load(); + Initialize(); } /// @@ -82,6 +84,52 @@ namespace Artemis.Core internal DataBindingModifierEntity Entity { get; set; } + + /// + public void Save() + { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + + if (!DataBinding.Entity.Modifiers.Contains(Entity)) + DataBinding.Entity.Modifiers.Add(Entity); + + // Modifier + if (ModifierType != null) + { + Entity.ModifierType = ModifierType.GetType().Name; + Entity.ModifierTypePluginGuid = ModifierType.PluginInfo.Guid; + } + + // General + Entity.Order = Order; + Entity.ParameterType = (int) ParameterType; + + // Parameter + if (ParameterDataModel != null) + { + Entity.ParameterDataModelGuid = ParameterDataModel.PluginInfo.Guid; + Entity.ParameterPropertyPath = ParameterPropertyPath; + } + + Entity.ParameterStaticValue = JsonConvert.SerializeObject(ParameterStaticValue); + } + + /// + public void Load() + { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + + // Modifier type is done during Initialize + + // General + Order = Entity.Order; + ParameterType = (ProfileRightSideType) Entity.ParameterType; + + // Parameter is done during initialize + } + /// /// Applies the modifier to the provided value /// @@ -89,6 +137,9 @@ namespace Artemis.Core /// The modified value public object Apply(object currentValue) { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + if (ModifierType == null) return currentValue; @@ -113,6 +164,9 @@ namespace Artemis.Core /// public void UpdateModifierType(DataBindingModifierType modifierType) { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + // Calling CreateExpression will clear compiled expressions if (modifierType == null) { @@ -139,6 +193,9 @@ namespace Artemis.Core /// The path pointing to the parameter inside the data model public void UpdateParameter(DataModel dataModel, string path) { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + if (dataModel != null && path == null) throw new ArtemisCoreException("If a data model is provided, a path is also required"); if (dataModel == null && path != null) @@ -163,6 +220,9 @@ namespace Artemis.Core /// The static value to use as a parameter public void UpdateParameter(object staticValue) { + if (_disposed) + throw new ObjectDisposedException("DataBindingModifier"); + ParameterType = ProfileRightSideType.Static; ParameterDataModel = null; ParameterPropertyPath = null; @@ -183,12 +243,17 @@ namespace Artemis.Core CreateExpression(); } - internal void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService) + private void Initialize() { + DataBindingModifierTypeStore.DataBindingModifierAdded += DataBindingModifierTypeStoreOnDataBindingModifierAdded; + DataBindingModifierTypeStore.DataBindingModifierRemoved += DataBindingModifierTypeStoreOnDataBindingModifierRemoved; + DataModelStore.DataModelAdded += DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved += DataModelStoreOnDataModelRemoved; + // Modifier type if (Entity.ModifierTypePluginGuid != null && ModifierType == null) { - var modifierType = dataBindingService.GetModifierType(Entity.ModifierTypePluginGuid.Value, Entity.ModifierType); + var modifierType = DataBindingModifierTypeStore.Get(Entity.ModifierTypePluginGuid.Value, Entity.ModifierType)?.DataBindingModifierType; if (modifierType != null) UpdateModifierType(modifierType); } @@ -196,7 +261,7 @@ namespace Artemis.Core // Dynamic parameter if (ParameterType == ProfileRightSideType.Dynamic && Entity.ParameterDataModelGuid != null && ParameterDataModel == null) { - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.ParameterDataModelGuid.Value); + var dataModel = DataModelStore.Get(Entity.ParameterDataModelGuid.Value)?.DataModel; if (dataModel != null && dataModel.ContainsPath(Entity.ParameterPropertyPath)) UpdateParameter(dataModel, Entity.ParameterPropertyPath); } @@ -214,7 +279,7 @@ namespace Artemis.Core // If deserialization fails, use the type's default catch (JsonSerializationException e) { - dataBindingService.LogModifierDeserializationFailure(GetType().Name, e); + DeserializationLogger.LogModifierDeserializationFailure(GetType().Name, e); staticValue = Activator.CreateInstance(targetType); } @@ -222,39 +287,6 @@ namespace Artemis.Core } } - /// - public void Save() - { - if (!DataBinding.Entity.Modifiers.Contains(Entity)) - DataBinding.Entity.Modifiers.Add(Entity); - - // Modifier - Entity.ModifierType = ModifierType?.GetType().Name; - Entity.ModifierTypePluginGuid = ModifierType?.PluginInfo.Guid; - - // General - Entity.Order = Order; - Entity.ParameterType = (int) ParameterType; - - // Parameter - Entity.ParameterDataModelGuid = ParameterDataModel?.PluginInfo.Guid; - Entity.ParameterPropertyPath = ParameterPropertyPath; - Entity.ParameterStaticValue = JsonConvert.SerializeObject(ParameterStaticValue); - } - - /// - public void Load() - { - // Modifier type is done during Initialize - - // General - Order = Entity.Order; - ParameterType = (ProfileRightSideType) Entity.ParameterType; - - // Parameter is done during initialize - } - - private void CreateExpression() { CompiledParameterAccessor = null; @@ -286,5 +318,51 @@ namespace Artemis.Core Expression.Property ); } + + #region Event handlers + + private void DataBindingModifierTypeStoreOnDataBindingModifierAdded(object sender, DataBindingModifierTypeStoreEvent e) + { + if (ModifierType != null) + return; + + var modifierType = e.TypeRegistration.DataBindingModifierType; + if (modifierType.PluginInfo.Guid == Entity.ModifierTypePluginGuid && modifierType.GetType().Name == Entity.ModifierType) + UpdateModifierType(modifierType); + } + + private void DataBindingModifierTypeStoreOnDataBindingModifierRemoved(object sender, DataBindingModifierTypeStoreEvent e) + { + if (e.TypeRegistration.DataBindingModifierType == ModifierType) + UpdateModifierType(null); + } + + private void DataModelStoreOnDataModelAdded(object sender, DataModelStoreEvent e) + { + var dataModel = e.Registration.DataModel; + if (dataModel.PluginInfo.Guid == Entity.ParameterDataModelGuid && dataModel.ContainsPath(Entity.ParameterPropertyPath)) + UpdateParameter(dataModel, Entity.ParameterPropertyPath); + } + + private void DataModelStoreOnDataModelRemoved(object sender, DataModelStoreEvent e) + { + if (e.Registration.DataModel != ParameterDataModel) + return; + ParameterDataModel = null; + CompiledParameterAccessor = null; + } + + #endregion + + /// + public void Dispose() + { + _disposed = true; + + DataBindingModifierTypeStore.DataBindingModifierAdded -= DataBindingModifierTypeStoreOnDataBindingModifierAdded; + DataBindingModifierTypeStore.DataBindingModifierRemoved -= DataBindingModifierTypeStoreOnDataBindingModifierRemoved; + DataModelStore.DataModelAdded -= DataModelStoreOnDataModelAdded; + DataModelStore.DataModelRemoved -= DataModelStoreOnDataModelRemoved; + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs b/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs index 6776a9e29..a609b1b3a 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/IDataBinding.cs @@ -1,20 +1,14 @@ -using Artemis.Core.DataModelExpansions; -using Artemis.Core.Services; +using System; +using Artemis.Core.DataModelExpansions; namespace Artemis.Core { /// - /// Represents a data binding that binds a certain to a value inside a + /// Represents a data binding that binds a certain to a value inside a + /// /// - public interface IDataBinding : IStorageModel, IUpdateModel + public interface IDataBinding : IStorageModel, IUpdateModel, IDisposable { - /// - /// (Re)initializes the data binding - /// - /// - /// - void Initialize(IDataModelService dataModelService, IDataBindingService dataBindingService); - /// /// Applies the data binding to the layer property /// diff --git a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs index 1192894eb..6f920c0a1 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/IDataBindingModifier.cs @@ -1,9 +1,11 @@ -namespace Artemis.Core +using System; + +namespace Artemis.Core { /// /// Modifies a data model value in a way defined by the modifier type /// - public interface IDataBindingModifier : IStorageModel + public interface IDataBindingModifier : IStorageModel, IDisposable { } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/Abstract/DataBindingModifierType.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/Abstract/DataBindingModifierType.cs index 2e01954bf..7f08e7a5a 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/Abstract/DataBindingModifierType.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modifiers/Abstract/DataBindingModifierType.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.Services; namespace Artemis.Core { @@ -10,9 +9,6 @@ namespace Artemis.Core /// public abstract class DataBindingModifierType { - private IDataBindingService _dataBindingService; - private bool _registered; - /// /// Gets the plugin info this data binding modifier belongs to /// Note: Not set until after registering @@ -63,35 +59,5 @@ namespace Artemis.Core /// /// The modified value, must be a value of a type contained in public abstract object Apply(object currentValue, object parameterValue); - - internal void Register(PluginInfo pluginInfo, IDataBindingService dataBindingService) - { - if (_registered) - return; - - PluginInfo = pluginInfo; - _dataBindingService = dataBindingService; - - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.PluginDisabled += InstanceOnPluginDisabled; - - _registered = true; - } - - internal void Unsubscribe() - { - if (!_registered) - return; - - if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.PluginDisabled -= InstanceOnPluginDisabled; - _registered = false; - } - - private void InstanceOnPluginDisabled(object sender, EventArgs e) - { - // The service will call Unsubscribe - _dataBindingService.RemoveModifierType(this); - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs index ce10a1bd0..4a4c43130 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs @@ -1,4 +1,5 @@ -using Artemis.Storage.Entities.Profile; +using System; +using Artemis.Storage.Entities.Profile; namespace Artemis.Core { @@ -9,7 +10,7 @@ namespace Artemis.Core /// initialize these for you. /// /// - public interface ILayerProperty : IStorageModel, IUpdateModel + public interface ILayerProperty : IStorageModel, IUpdateModel, IDisposable { /// /// Initializes the layer property diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs index acd4c9965..ed49633ad 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; using Newtonsoft.Json; @@ -19,6 +18,8 @@ namespace Artemis.Core /// The type of property encapsulated in this layer property public abstract class LayerProperty : ILayerProperty { + private bool _disposed; + /// /// Creates a new instance of the class /// @@ -37,6 +38,9 @@ namespace Artemis.Core /// public void Update(double deltaTime) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + CurrentValue = BaseValue; UpdateKeyframes(); @@ -136,6 +140,9 @@ namespace Artemis.Core /// public void SetCurrentValue(T value, TimeSpan? time) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (time == null || !KeyframesEnabled || !KeyframesSupported) BaseValue = value; else @@ -159,6 +166,9 @@ namespace Artemis.Core /// public void ApplyDefaultValue() { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + BaseValue = DefaultValue; CurrentValue = DefaultValue; } @@ -212,6 +222,9 @@ namespace Artemis.Core /// The keyframe to add public void AddKeyframe(LayerPropertyKeyframe keyframe) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (_keyframes.Contains(keyframe)) return; @@ -229,6 +242,9 @@ namespace Artemis.Core /// The keyframe to remove public LayerPropertyKeyframe CopyKeyframe(LayerPropertyKeyframe keyframe) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + var newKeyframe = new LayerPropertyKeyframe( keyframe.Value, keyframe.Position, @@ -246,6 +262,9 @@ namespace Artemis.Core /// The keyframe to remove public void RemoveKeyframe(LayerPropertyKeyframe keyframe) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (!_keyframes.Contains(keyframe)) return; @@ -260,6 +279,9 @@ namespace Artemis.Core /// public void ClearKeyframes() { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + var keyframes = new List>(_keyframes); foreach (var layerPropertyKeyframe in keyframes) RemoveKeyframe(layerPropertyKeyframe); @@ -313,6 +335,9 @@ namespace Artemis.Core public DataBindingRegistration GetDataBindingRegistration(string propertyName) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + var match = _dataBindingRegistrations.FirstOrDefault(r => r is DataBindingRegistration registration && registration.Property.Name == propertyName); return (DataBindingRegistration) match; @@ -320,6 +345,9 @@ namespace Artemis.Core public void RegisterDataBindingProperty(Expression> propertyLambda, DataBindingConverter converter) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + // If the lambda references to itself, use the property info of public new T CurrentValue PropertyInfo propertyInfo; string path = null; @@ -353,6 +381,9 @@ namespace Artemis.Core /// The newly created data binding public DataBinding EnableDataBinding(DataBindingRegistration dataBindingRegistration) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (dataBindingRegistration.LayerProperty != this) throw new ArtemisCoreException("Cannot enable a data binding using a data binding registration of a different layer property"); @@ -368,6 +399,9 @@ namespace Artemis.Core /// The data binding to remove public void DisableDataBinding(DataBinding dataBinding) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + _dataBindings.Remove(dataBinding); } @@ -380,12 +414,6 @@ namespace Artemis.Core } } - internal void InitializeDataBindings(IDataModelService dataModelService, IDataBindingService dataBindingService) - { - foreach (var dataBinding in _dataBindings) - dataBinding.Initialize(dataModelService, dataBindingService); - } - #endregion #region Storage @@ -402,6 +430,9 @@ namespace Artemis.Core /// public void Initialize(RenderProfileElement profileElement, LayerPropertyGroup group, PropertyEntity entity, bool fromStorage, PropertyDescriptionAttribute description) { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + _isInitialized = true; ProfileElement = profileElement ?? throw new ArgumentNullException(nameof(profileElement)); @@ -409,13 +440,16 @@ namespace Artemis.Core Entity = entity ?? throw new ArgumentNullException(nameof(entity)); PropertyDescription = description ?? throw new ArgumentNullException(nameof(description)); IsLoadedFromStorage = fromStorage; - + LayerPropertyGroup.PropertyGroupUpdating += (sender, args) => Update(args.DeltaTime); } /// public void Load() { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (!_isInitialized) throw new ArtemisCoreException("Layer property is not yet initialized"); @@ -467,6 +501,9 @@ namespace Artemis.Core /// public void Save() { + if (_disposed) + throw new ObjectDisposedException("LayerProperty"); + if (!_isInitialized) throw new ArtemisCoreException("Layer property is not yet initialized"); @@ -550,5 +587,14 @@ namespace Artemis.Core } #endregion + + /// + public void Dispose() + { + _disposed = true; + + foreach (var dataBinding in _dataBindings) + dataBinding.Dispose(); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index b6720b92f..bf423342c 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -6,7 +6,6 @@ using System.Reflection; using Artemis.Core.LayerBrushes; using Artemis.Core.LayerEffects; using Artemis.Core.Properties; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; namespace Artemis.Core @@ -15,6 +14,7 @@ namespace Artemis.Core { private readonly List _layerProperties; private readonly List _layerPropertyGroups; + private bool _disposed; private bool _isHidden; protected LayerPropertyGroup() @@ -23,6 +23,9 @@ namespace Artemis.Core _layerPropertyGroups = new List(); } + /// + /// Gets the description of this group + /// public PropertyGroupDescriptionAttribute GroupDescription { get; internal set; } /// @@ -83,19 +86,30 @@ namespace Artemis.Core /// public ReadOnlyCollection LayerPropertyGroups => _layerPropertyGroups.AsReadOnly(); + #region IDisposable + /// public void Dispose() { + _disposed = true; DisableProperties(); + + foreach (var layerProperty in _layerProperties) + layerProperty.Dispose(); foreach (var layerPropertyGroup in _layerPropertyGroups) layerPropertyGroup.Dispose(); } + #endregion + /// /// Recursively gets all layer properties on this group and any subgroups /// public IReadOnlyCollection GetAllLayerProperties() { + if (_disposed) + throw new ObjectDisposedException("LayerPropertyGroup"); + if (!PropertiesInitialized) return new List(); @@ -240,7 +254,7 @@ namespace Artemis.Core return entity; } - + #region Events internal event EventHandler PropertyGroupUpdating; diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index e23874cfe..10806d755 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -34,7 +34,7 @@ namespace Artemis.Core UndoStack = new Stack(); RedoStack = new Stack(); - ApplyToProfile(); + Load(); } public ProfileModule Module { get; } @@ -86,7 +86,7 @@ namespace Artemis.Core return (Folder) Children.Single(); } - public void ApplyToProfile() + internal override void Load() { if (_disposed) throw new ObjectDisposedException("Profile"); diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index bc3d86cb6..81fd839a1 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -12,6 +12,12 @@ namespace Artemis.Core { public abstract class RenderProfileElement : ProfileElement { + protected RenderProfileElement() + { + LayerEffectStore.LayerEffectAdded += LayerEffectStoreOnLayerEffectAdded; + LayerEffectStore.LayerEffectRemoved += LayerEffectStoreOnLayerEffectRemoved; + } + internal void ApplyRenderElementDefaults() { MainSegmentLength = TimeSpan.FromSeconds(5); @@ -270,6 +276,7 @@ namespace Artemis.Core } } + internal void ActivateLayerEffect(BaseLayerEffect layerEffect) { _layerEffects.Add(layerEffect); @@ -285,6 +292,16 @@ namespace Artemis.Core OnLayerEffectsUpdated(); } + private void LayerEffectStoreOnLayerEffectRemoved(object? sender, LayerEffectStoreEvent e) + { + throw new NotImplementedException(); + } + + private void LayerEffectStoreOnLayerEffectAdded(object? sender, LayerEffectStoreEvent e) + { + ActivateEffects(); + } + #endregion #region Conditions diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 49c575d8e..f51c51a69 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -17,21 +17,17 @@ namespace Artemis.Core.Services private readonly ILogger _logger; private readonly IPluginService _pluginService; private readonly IProfileRepository _profileRepository; - private readonly IRenderElementService _renderElementService; private readonly ISurfaceService _surfaceService; - internal ProfileService(ILogger logger, IPluginService pluginService, ISurfaceService surfaceService, IRenderElementService renderElementService, IProfileRepository profileRepository) + internal ProfileService(ILogger logger, IPluginService pluginService, ISurfaceService surfaceService, IProfileRepository profileRepository) { _logger = logger; _pluginService = pluginService; _surfaceService = surfaceService; - _renderElementService = renderElementService; _profileRepository = profileRepository; _surfaceService.ActiveSurfaceConfigurationSelected += OnActiveSurfaceConfigurationSelected; _surfaceService.SurfaceConfigurationUpdated += OnSurfaceConfigurationUpdated; - _pluginService.PluginEnabled += OnPluginToggled; - _pluginService.PluginDisabled += OnPluginToggled; } public JsonSerializerSettings MementoSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}; @@ -186,7 +182,7 @@ namespace Artemis.Core.Services profile.RedoStack.Push(memento); profile.ProfileEntity = JsonConvert.DeserializeObject(top, MementoSettings); - profile.ApplyToProfile(); + profile.Load(); InstantiateProfile(profile); } @@ -210,7 +206,7 @@ namespace Artemis.Core.Services profile.UndoStack.Push(memento); profile.ProfileEntity = JsonConvert.DeserializeObject(top, MementoSettings); - profile.ApplyToProfile(); + profile.Load(); InstantiateProfile(profile); _logger.Debug("Redo profile update - Success"); @@ -221,9 +217,6 @@ namespace Artemis.Core.Services public void InstantiateProfile(Profile profile) { profile.PopulateLeds(_surfaceService.ActiveSurface); - InitializeLayerProperties(profile); - InstantiateLayers(profile); - InstantiateFolders(profile); } public string ExportProfile(ProfileDescriptor profileDescriptor) @@ -268,67 +261,7 @@ namespace Artemis.Core.Services _profileRepository.Save(profileEntity); } } - - /// - /// Initializes the properties on the layers of the given profile - /// - /// - private void InitializeLayerProperties(Profile profile) - { - foreach (var layer in profile.GetAllLayers()) - { - if (!layer.General.PropertiesInitialized) - layer.General.Initialize(layer, "General.", Constants.CorePluginInfo); - if (!layer.Transform.PropertiesInitialized) - layer.Transform.Initialize(layer, "Transform.", Constants.CorePluginInfo); - } - } - - /// - /// Instantiates all plugin-related classes on the folders of the given profile - /// - private void InstantiateFolders(Profile profile) - { - foreach (var folder in profile.GetAllFolders()) - { - // Instantiate effects - _renderElementService.InstantiateLayerEffects(folder); - // Remove effects of plugins that are disabled - var disabledEffects = new List(folder.LayerEffects.Where(layerLayerEffect => !layerLayerEffect.PluginInfo.Enabled)); - foreach (var layerLayerEffect in disabledEffects) - _renderElementService.RemoveLayerEffect(layerLayerEffect); - - _renderElementService.InstantiateDisplayConditions(folder); - _renderElementService.InstantiateDataBindings(folder); - } - } - - /// - /// Instantiates all plugin-related classes on the layers of the given profile - /// - private void InstantiateLayers(Profile profile) - { - foreach (var layer in profile.GetAllLayers()) - { - // Instantiate brush - if (layer.LayerBrush == null) - _renderElementService.InstantiateLayerBrush(layer); - // Remove brush if plugin is disabled - else if (!layer.LayerBrush.PluginInfo.Enabled) - _renderElementService.DeactivateLayerBrush(layer); - - // Instantiate effects - _renderElementService.InstantiateLayerEffects(layer); - // Remove effects of plugins that are disabled - var disabledEffects = new List(layer.LayerEffects.Where(layerLayerEffect => !layerLayerEffect.PluginInfo.Enabled)); - foreach (var layerLayerEffect in disabledEffects) - _renderElementService.RemoveLayerEffect(layerLayerEffect); - - _renderElementService.InstantiateDisplayConditions(layer); - _renderElementService.InstantiateDataBindings(layer); - } - } - + /// /// Populates all missing LEDs on all currently active profiles /// @@ -339,21 +272,7 @@ namespace Artemis.Core.Services foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList()) profileModule.ActiveProfile.PopulateLeds(surface); } - - - /// - /// Instantiates all missing plugin-related classes on the profile trees of all currently active profiles - /// - private void ActiveProfilesInstantiatePlugins() - { - var profileModules = _pluginService.GetPluginsOfType(); - foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList()) - { - InstantiateLayers(profileModule.ActiveProfile); - InstantiateFolders(profileModule.ActiveProfile); - } - } - + #region Event handlers private void OnActiveSurfaceConfigurationSelected(object sender, SurfaceConfigurationEventArgs e) @@ -366,15 +285,7 @@ namespace Artemis.Core.Services if (e.Surface.IsActive) ActiveProfilesPopulateLeds(e.Surface); } - - private void OnPluginToggled(object sender, PluginEventArgs e) - { - if (e.PluginInfo.Instance is LayerBrushProvider) - ActiveProfilesInstantiatePlugins(); - if (e.PluginInfo.Instance is LayerEffectProvider) - ActiveProfilesInstantiatePlugins(); - } - + #endregion } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/ColorBrushProperties.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/ColorBrushProperties.cs index b840bfc07..beeaec69a 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/ColorBrushProperties.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/ColorBrushProperties.cs @@ -37,21 +37,26 @@ namespace Artemis.Plugins.LayerBrushes.Color.PropertyGroups protected override void EnableProperties() { - GradientType.BaseValueChanged += OnBaseValueChanged; + GradientType.BaseValueChanged += GradientTypeOnBaseValueChanged; if (ProfileElement is Layer layer) - layer.General.ResizeMode.BaseValueChanged += OnBaseValueChanged; + layer.General.ResizeMode.BaseValueChanged += ResizeModeOnBaseValueChanged; UpdateVisibility(); } protected override void DisableProperties() { - GradientType.BaseValueChanged -= OnBaseValueChanged; + GradientType.BaseValueChanged -= GradientTypeOnBaseValueChanged; if (ProfileElement is Layer layer) - layer.General.ResizeMode.BaseValueChanged -= OnBaseValueChanged; + layer.General.ResizeMode.BaseValueChanged -= ResizeModeOnBaseValueChanged; } - private void OnBaseValueChanged(object sender, LayerPropertyEventArgs e) + private void GradientTypeOnBaseValueChanged(object sender, LayerPropertyEventArgs e) + { + UpdateVisibility(); + } + + private void ResizeModeOnBaseValueChanged(object sender, LayerPropertyEventArgs e) { UpdateVisibility(); } diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/RadialGradientProperties.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/RadialGradientProperties.cs index 6af1093b9..21afb4bf5 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/RadialGradientProperties.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/PropertyGroups/RadialGradientProperties.cs @@ -18,7 +18,7 @@ namespace Artemis.Plugins.LayerBrushes.Color.PropertyGroups protected override void EnableProperties() { if (ProfileElement is Layer layer) - layer.General.ResizeMode.BaseValueChanged += OnBaseValueChanged; + layer.General.ResizeMode.BaseValueChanged += ResizeModeOnBaseValueChanged; UpdateVisibility(); } @@ -26,10 +26,10 @@ namespace Artemis.Plugins.LayerBrushes.Color.PropertyGroups protected override void DisableProperties() { if (ProfileElement is Layer layer) - layer.General.ResizeMode.BaseValueChanged -= OnBaseValueChanged; + layer.General.ResizeMode.BaseValueChanged -= ResizeModeOnBaseValueChanged; } - private void OnBaseValueChanged(object sender, LayerPropertyEventArgs e) + private void ResizeModeOnBaseValueChanged(object sender, LayerPropertyEventArgs e) { UpdateVisibility(); }