From 11de30318e0eb91fc38ea3bd34ebfd39052567fc Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 9 Sep 2020 19:56:06 +0200 Subject: [PATCH] Core - Added stores for the different register-able types Profiles - Refactored large parts of the profile structure to use these stores --- .../Artemis.Core.csproj.DotSettings | 7 + .../Events/{ => Plugins}/PluginEventArgs.cs | 0 .../DataBindingPropertyUpdatedEvent.cs | 0 .../{ => Profiles}/LayerPropertyEventArgs.cs | 0 .../LayerPropertyGroupUpdatingEventArgs.cs | 0 .../Stores/ConditionOperatorStoreEvent.cs | 12 + .../DataBindingModifierTypeStoreEvent.cs | 12 + .../Events/Stores/DataModelStoreEvent.cs | 12 + .../Events/Stores/LayerBrushStoreEvent.cs | 12 + .../Events/Stores/LayerEffectStoreEvent.cs | 12 + .../Abstract/DisplayConditionPart.cs | 1 - ...ditionOperator.cs => ConditionOperator.cs} | 38 +-- .../Conditions/DisplayConditionGroup.cs | 7 - .../Conditions/DisplayConditionList.cs | 11 +- .../DisplayConditionListPredicate.cs | 23 +- .../Conditions/DisplayConditionPredicate.cs | 31 ++- .../Operators/EqualsConditionOperator.cs | 2 +- .../Operators/GreaterThanConditionOperator.cs | 2 +- .../GreaterThanOrEqualConditionOperator.cs | 2 +- .../Operators/LessThanConditionOperator.cs | 2 +- .../LessThanOrEqualConditionOperator.cs | 2 +- .../Operators/NotEqualConditionOperator.cs | 2 +- .../StringContainsConditionOperator.cs | 2 +- .../StringEndsWithConditionOperator.cs | 2 +- .../StringEqualsConditionOperator.cs | 2 +- .../StringNotContainsConditionOperator.cs | 2 +- .../StringNotEqualConditionOperator.cs | 2 +- .../Operators/StringNullConditionOperator.cs | 2 +- .../StringStartsWithConditionOperator.cs | 2 +- src/Artemis.Core/Models/Profile/Folder.cs | 49 ++-- src/Artemis.Core/Models/Profile/Layer.cs | 113 +++++--- .../Models/Profile/LayerPropertyGroup.cs | 8 - src/Artemis.Core/Models/Profile/Profile.cs | 6 +- .../Models/Profile/ProfileElement.cs | 113 +++++--- .../Models/Profile/RenderProfileElement.cs | 68 +++-- .../Plugins/DataModelExpansions/DataModel.cs | 6 + .../DataModelExpansions/DataModelExpansion.cs | 3 +- .../LayerBrushes/LayerBrushDescriptor.cs | 24 ++ .../LayerEffects/LayerEffectDescriptor.cs | 32 +++ src/Artemis.Core/Plugins/Modules/Module.cs | 1 + .../Plugins/Modules/ProfileModule.cs | 3 +- src/Artemis.Core/Services/CoreService.cs | 9 +- .../Services/DataBindingService.cs | 106 -------- src/Artemis.Core/Services/DataModelService.cs | 252 ------------------ .../Services/Interfaces/ICoreService.cs | 3 + .../Services/Interfaces/IDataModelService.cs | 91 ------- .../Services/Interfaces/IDeviceService.cs | 3 + .../Interfaces/IRenderElementService.cs | 59 ---- .../Services/Interfaces/IRgbService.cs | 17 +- .../Registration/ConditionOperatorService.cs | 64 +++++ .../Registration/DataBindingService.cs | 49 ++++ .../Services/Registration/DataModelService.cs | 86 ++++++ .../Interfaces/IConditionOperatorService.cs | 37 +++ .../Interfaces/IDataBindingService.cs | 22 +- .../Interfaces/IDataModelService.cs | 46 ++++ .../Interfaces/ILayerBrushService.cs | 26 ++ .../Interfaces/ILayerEffectService.cs | 27 ++ .../Registration/LayerBrushService.cs | 38 +++ .../Registration/LayerEffectService.cs | 39 +++ .../Services/RenderElementService.cs | 168 ------------ src/Artemis.Core/Services/RgbService.cs | 2 +- .../Services/Storage/ProfileService.cs | 6 +- .../Stores/ConditionOperatorStore.cs | 90 +++++++ .../Stores/DataBindingModifierTypeStore.cs | 90 +++++++ src/Artemis.Core/Stores/DataModelStore.cs | 75 ++++++ src/Artemis.Core/Stores/LayerBrushStore.cs | 75 ++++++ src/Artemis.Core/Stores/LayerEffectStore.cs | 75 ++++++ .../ConditionOperatorRegistration.cs | 40 +++ .../DataBindingModifierTypeRegistration.cs | 40 +++ .../Registrations/DataModelRegistration.cs | 41 +++ .../Registrations/LayerBrushRegistration.cs | 41 +++ .../Registrations/LayerEffectRegistration.cs | 41 +++ .../Utilities/DeserializationLogger.cs | 44 +++ .../DisplayConditionListPredicateViewModel.cs | 14 +- .../DisplayConditionPredicateViewModel.cs | 14 +- 75 files changed, 1526 insertions(+), 934 deletions(-) rename src/Artemis.Core/Events/{ => Plugins}/PluginEventArgs.cs (100%) rename src/Artemis.Core/Events/{ => Profiles}/DataBindingPropertyUpdatedEvent.cs (100%) rename src/Artemis.Core/Events/{ => Profiles}/LayerPropertyEventArgs.cs (100%) rename src/Artemis.Core/Events/{ => Profiles}/LayerPropertyGroupUpdatingEventArgs.cs (100%) create mode 100644 src/Artemis.Core/Events/Stores/ConditionOperatorStoreEvent.cs create mode 100644 src/Artemis.Core/Events/Stores/DataBindingModifierTypeStoreEvent.cs create mode 100644 src/Artemis.Core/Events/Stores/DataModelStoreEvent.cs create mode 100644 src/Artemis.Core/Events/Stores/LayerBrushStoreEvent.cs create mode 100644 src/Artemis.Core/Events/Stores/LayerEffectStoreEvent.cs rename src/Artemis.Core/Models/Profile/Conditions/{DisplayConditionOperator.cs => ConditionOperator.cs} (61%) delete mode 100644 src/Artemis.Core/Services/DataBindingService.cs delete mode 100644 src/Artemis.Core/Services/DataModelService.cs delete mode 100644 src/Artemis.Core/Services/Interfaces/IDataModelService.cs delete mode 100644 src/Artemis.Core/Services/Interfaces/IRenderElementService.cs create mode 100644 src/Artemis.Core/Services/Registration/ConditionOperatorService.cs create mode 100644 src/Artemis.Core/Services/Registration/DataBindingService.cs create mode 100644 src/Artemis.Core/Services/Registration/DataModelService.cs create mode 100644 src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs rename src/Artemis.Core/Services/{ => Registration}/Interfaces/IDataBindingService.cs (60%) create mode 100644 src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs create mode 100644 src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs create mode 100644 src/Artemis.Core/Services/Registration/Interfaces/ILayerEffectService.cs create mode 100644 src/Artemis.Core/Services/Registration/LayerBrushService.cs create mode 100644 src/Artemis.Core/Services/Registration/LayerEffectService.cs delete mode 100644 src/Artemis.Core/Services/RenderElementService.cs create mode 100644 src/Artemis.Core/Stores/ConditionOperatorStore.cs create mode 100644 src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs create mode 100644 src/Artemis.Core/Stores/DataModelStore.cs create mode 100644 src/Artemis.Core/Stores/LayerBrushStore.cs create mode 100644 src/Artemis.Core/Stores/LayerEffectStore.cs create mode 100644 src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs create mode 100644 src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs create mode 100644 src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs create mode 100644 src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs create mode 100644 src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs create mode 100644 src/Artemis.Core/Utilities/DeserializationLogger.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings index 77021d436..7f651acb6 100644 --- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings +++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings @@ -1,5 +1,8 @@  True + True + True + True True True True @@ -29,6 +32,10 @@ True True True + True + True True True + True + True True \ No newline at end of file diff --git a/src/Artemis.Core/Events/PluginEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs similarity index 100% rename from src/Artemis.Core/Events/PluginEventArgs.cs rename to src/Artemis.Core/Events/Plugins/PluginEventArgs.cs diff --git a/src/Artemis.Core/Events/DataBindingPropertyUpdatedEvent.cs b/src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs similarity index 100% rename from src/Artemis.Core/Events/DataBindingPropertyUpdatedEvent.cs rename to src/Artemis.Core/Events/Profiles/DataBindingPropertyUpdatedEvent.cs diff --git a/src/Artemis.Core/Events/LayerPropertyEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs similarity index 100% rename from src/Artemis.Core/Events/LayerPropertyEventArgs.cs rename to src/Artemis.Core/Events/Profiles/LayerPropertyEventArgs.cs diff --git a/src/Artemis.Core/Events/LayerPropertyGroupUpdatingEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs similarity index 100% rename from src/Artemis.Core/Events/LayerPropertyGroupUpdatingEventArgs.cs rename to src/Artemis.Core/Events/Profiles/LayerPropertyGroupUpdatingEventArgs.cs diff --git a/src/Artemis.Core/Events/Stores/ConditionOperatorStoreEvent.cs b/src/Artemis.Core/Events/Stores/ConditionOperatorStoreEvent.cs new file mode 100644 index 000000000..fb81fa23f --- /dev/null +++ b/src/Artemis.Core/Events/Stores/ConditionOperatorStoreEvent.cs @@ -0,0 +1,12 @@ +namespace Artemis.Core +{ + internal class ConditionOperatorStoreEvent + { + public ConditionOperatorStoreEvent(ConditionOperatorRegistration registration) + { + Registration = registration; + } + + public ConditionOperatorRegistration Registration { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/Stores/DataBindingModifierTypeStoreEvent.cs b/src/Artemis.Core/Events/Stores/DataBindingModifierTypeStoreEvent.cs new file mode 100644 index 000000000..c954a7f60 --- /dev/null +++ b/src/Artemis.Core/Events/Stores/DataBindingModifierTypeStoreEvent.cs @@ -0,0 +1,12 @@ +namespace Artemis.Core +{ + internal class DataBindingModifierTypeStoreEvent + { + public DataBindingModifierTypeStoreEvent(DataBindingModifierTypeRegistration typeRegistration) + { + TypeRegistration = typeRegistration; + } + + public DataBindingModifierTypeRegistration TypeRegistration { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/Stores/DataModelStoreEvent.cs b/src/Artemis.Core/Events/Stores/DataModelStoreEvent.cs new file mode 100644 index 000000000..eb1132422 --- /dev/null +++ b/src/Artemis.Core/Events/Stores/DataModelStoreEvent.cs @@ -0,0 +1,12 @@ +namespace Artemis.Core +{ + internal class DataModelStoreEvent + { + public DataModelStoreEvent(DataModelRegistration registration) + { + Registration = registration; + } + + public DataModelRegistration Registration { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/Stores/LayerBrushStoreEvent.cs b/src/Artemis.Core/Events/Stores/LayerBrushStoreEvent.cs new file mode 100644 index 000000000..6d80a46fb --- /dev/null +++ b/src/Artemis.Core/Events/Stores/LayerBrushStoreEvent.cs @@ -0,0 +1,12 @@ +namespace Artemis.Core +{ + internal class LayerBrushStoreEvent + { + public LayerBrushStoreEvent(LayerBrushRegistration registration) + { + Registration = registration; + } + + public LayerBrushRegistration Registration { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Events/Stores/LayerEffectStoreEvent.cs b/src/Artemis.Core/Events/Stores/LayerEffectStoreEvent.cs new file mode 100644 index 000000000..8abcecb7f --- /dev/null +++ b/src/Artemis.Core/Events/Stores/LayerEffectStoreEvent.cs @@ -0,0 +1,12 @@ +namespace Artemis.Core +{ + internal class LayerEffectStoreEvent + { + public LayerEffectStoreEvent(LayerEffectRegistration registration) + { + Registration = registration; + } + + public LayerEffectRegistration Registration { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs index 2ae490f56..2669afc17 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs @@ -60,7 +60,6 @@ namespace Artemis.Core /// public abstract bool EvaluateObject(object target); - internal abstract void Initialize(IDataModelService dataModelService); internal abstract void ApplyToEntity(); internal abstract DisplayConditionPartEntity GetEntity(); } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/ConditionOperator.cs similarity index 61% rename from src/Artemis.Core/Models/Profile/Conditions/DisplayConditionOperator.cs rename to src/Artemis.Core/Models/Profile/Conditions/ConditionOperator.cs index cb592b5e5..53ca9bd79 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/ConditionOperator.cs @@ -2,18 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using Artemis.Core.Services; namespace Artemis.Core { /// - /// A display condition operator is used by the conditions system to perform a specific boolean check + /// A condition operator is used by the conditions system to perform a specific boolean check /// - public abstract class DisplayConditionOperator + public abstract class ConditionOperator { - private IDataModelService _dataModelService; - private bool _registered; - /// /// Gets the plugin info this condition operator belongs to /// Note: Not set until after registering @@ -57,35 +53,5 @@ namespace Artemis.Core /// The parameter on the right side of the expression /// public abstract BinaryExpression CreateExpression(Expression leftSide, Expression rightSide); - - internal void Register(PluginInfo pluginInfo, IDataModelService dataModelService) - { - if (_registered) - return; - - PluginInfo = pluginInfo; - _dataModelService = dataModelService; - - 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 - _dataModelService.RemoveConditionOperator(this); - } } } \ 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 c93bb0612..e68dd9e57 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; @@ -108,12 +107,6 @@ namespace Artemis.Core child.ApplyToEntity(); } - internal override void Initialize(IDataModelService dataModelService) - { - foreach (var child in Children) - child.Initialize(dataModelService); - } - internal override DisplayConditionPartEntity GetEntity() { return Entity; diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs index 4bb1a587d..bd9c54b76 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Linq; using System.Linq.Expressions; using Artemis.Core.DataModelExpansions; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; @@ -15,6 +14,8 @@ namespace Artemis.Core { Parent = parent; Entity = new DisplayConditionListEntity(); + + Initialize(); } public DisplayConditionList(DisplayConditionPart parent, DisplayConditionListEntity entity) @@ -22,6 +23,8 @@ namespace Artemis.Core Parent = parent; Entity = entity; ListOperator = (ListOperator) entity.ListOperator; + + Initialize(); } public DisplayConditionListEntity Entity { get; set; } @@ -120,13 +123,13 @@ namespace Artemis.Core return Entity; } - internal override void Initialize(IDataModelService dataModelService) + internal void Initialize() { if (Entity.ListDataModelGuid == null) return; // Get the data model and ensure the path is valid - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.ListDataModelGuid.Value); + var dataModel = DataModelStore.Get(Entity.ListDataModelGuid.Value)?.DataModel; if (dataModel == null || !dataModel.ContainsPath(Entity.ListPropertyPath)) return; @@ -143,8 +146,6 @@ namespace Artemis.Core Entity.Children.Clear(); AddChild(new DisplayConditionGroup(this)); } - - Children[0].Initialize(dataModelService); } } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs index 6afee4a2f..41c5890df 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.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.Abstract; using Artemis.Storage.Entities.Profile.Conditions; using Newtonsoft.Json; @@ -18,6 +17,7 @@ namespace Artemis.Core Entity = new DisplayConditionListPredicateEntity(); ApplyParentList(); + Initialize(); } public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity) @@ -27,12 +27,13 @@ namespace Artemis.Core PredicateType = (ProfileRightSideType) entity.PredicateType; ApplyParentList(); + Initialize(); } public DisplayConditionListPredicateEntity Entity { get; set; } public ProfileRightSideType PredicateType { get; set; } - public DisplayConditionOperator Operator { get; private set; } + public ConditionOperator Operator { get; private set; } public Type ListType { get; private set; } public DataModel ListDataModel { get; private set; } @@ -120,9 +121,9 @@ namespace Artemis.Core CreateExpression(); } - public void UpdateOperator(DisplayConditionOperator displayConditionOperator) + public void UpdateOperator(ConditionOperator conditionOperator) { - if (displayConditionOperator == null) + if (conditionOperator == null) { Operator = null; return; @@ -130,13 +131,13 @@ namespace Artemis.Core if (LeftPropertyPath == null) { - Operator = displayConditionOperator; + Operator = conditionOperator; return; } var leftType = GetTypeAtInnerPath(LeftPropertyPath); - if (displayConditionOperator.SupportsType(leftType)) - Operator = displayConditionOperator; + if (conditionOperator.SupportsType(leftType)) + Operator = conditionOperator; CreateExpression(); } @@ -203,7 +204,7 @@ namespace Artemis.Core Entity.OperatorType = Operator?.GetType().Name; } - internal override void Initialize(IDataModelService dataModelService) + internal void Initialize() { // Left side if (Entity.LeftPropertyPath != null && ListContainsInnerPath(Entity.LeftPropertyPath)) @@ -212,7 +213,7 @@ namespace Artemis.Core // Operator if (Entity.OperatorPluginGuid != null) { - var conditionOperator = dataModelService.GetConditionOperator(Entity.OperatorPluginGuid.Value, Entity.OperatorType); + var conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator; if (conditionOperator != null) UpdateOperator(conditionOperator); } @@ -241,7 +242,7 @@ namespace Artemis.Core // If deserialization fails, use the type's default catch (JsonSerializationException e) { - dataModelService.LogListPredicateDeserializationFailure(this, e); + DeserializationLogger.LogListPredicateDeserializationFailure(this, e); rightSideValue = Activator.CreateInstance(leftSideType); } @@ -255,7 +256,7 @@ namespace Artemis.Core } catch (JsonException e) { - dataModelService.LogListPredicateDeserializationFailure(this, e); + DeserializationLogger.LogListPredicateDeserializationFailure(this, e); } } } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs index 617de25f1..70a7a890a 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.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.Abstract; using Artemis.Storage.Entities.Profile.Conditions; using Newtonsoft.Json; @@ -25,6 +24,8 @@ namespace Artemis.Core Parent = parent; PredicateType = predicateType; Entity = new DisplayConditionPredicateEntity(); + + Initialize(); } /// @@ -37,6 +38,8 @@ namespace Artemis.Core Parent = parent; Entity = entity; PredicateType = (ProfileRightSideType) entity.PredicateType; + + Initialize(); } /// @@ -47,7 +50,7 @@ namespace Artemis.Core /// /// Gets the operator /// - public DisplayConditionOperator Operator { get; private set; } + public ConditionOperator Operator { get; private set; } /// /// Gets the currently used instance of the left data model @@ -175,11 +178,11 @@ namespace Artemis.Core /// /// Updates the operator of the predicate and re-compiles the expression /// - /// - public void UpdateOperator(DisplayConditionOperator displayConditionOperator) + /// + public void UpdateOperator(ConditionOperator conditionOperator) { // Calling CreateExpression will clear compiled expressions - if (displayConditionOperator == null) + if (conditionOperator == null) { Operator = null; CreateExpression(); @@ -189,18 +192,18 @@ namespace Artemis.Core // No need to clear compiled expressions, without a left data model they are already null if (LeftDataModel == null) { - Operator = displayConditionOperator; + Operator = conditionOperator; return; } var leftType = LeftDataModel.GetTypeAtPath(LeftPropertyPath); - if (!displayConditionOperator.SupportsType(leftType)) + if (!conditionOperator.SupportsType(leftType)) { - throw new ArtemisCoreException($"Cannot apply operator {displayConditionOperator.GetType().Name} to this predicate because " + + throw new ArtemisCoreException($"Cannot apply operator {conditionOperator.GetType().Name} to this predicate because " + $"it does not support left side type {leftType.Name}"); } - Operator = displayConditionOperator; + Operator = conditionOperator; CreateExpression(); } @@ -243,12 +246,12 @@ namespace Artemis.Core Entity.OperatorType = Operator?.GetType().Name; } - internal override void Initialize(IDataModelService dataModelService) + internal void Initialize() { // Left side if (Entity.LeftDataModelGuid != null) { - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.LeftDataModelGuid.Value); + var dataModel = DataModelStore.Get(Entity.LeftDataModelGuid.Value)?.DataModel; if (dataModel != null && dataModel.ContainsPath(Entity.LeftPropertyPath)) UpdateLeftSide(dataModel, Entity.LeftPropertyPath); } @@ -256,7 +259,7 @@ namespace Artemis.Core // Operator if (Entity.OperatorPluginGuid != null) { - var conditionOperator = dataModelService.GetConditionOperator(Entity.OperatorPluginGuid.Value, Entity.OperatorType); + var conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator; if (conditionOperator != null) UpdateOperator(conditionOperator); } @@ -264,7 +267,7 @@ namespace Artemis.Core // Right side dynamic if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightDataModelGuid != null) { - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.RightDataModelGuid.Value); + var dataModel = DataModelStore.Get(Entity.RightDataModelGuid.Value)?.DataModel; if (dataModel != null && dataModel.ContainsPath(Entity.RightPropertyPath)) UpdateRightSide(dataModel, Entity.RightPropertyPath); } @@ -286,7 +289,7 @@ namespace Artemis.Core // If deserialization fails, use the type's default catch (JsonSerializationException e) { - dataModelService.LogPredicateDeserializationFailure(this, e); + DeserializationLogger.LogPredicateDeserializationFailure(this, e); rightSideValue = Activator.CreateInstance(leftSideType); } diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/EqualsConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/EqualsConditionOperator.cs index 44388b7c1..87b60d484 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/EqualsConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/EqualsConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class EqualsConditionOperator : DisplayConditionOperator + internal class EqualsConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => new List {typeof(object)}; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanConditionOperator.cs index 37dbccadb..6fa3287a5 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class GreaterThanConditionOperator : DisplayConditionOperator + internal class GreaterThanConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => Constants.NumberTypes; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanOrEqualConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanOrEqualConditionOperator.cs index 578c20aab..5bd914abb 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanOrEqualConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/GreaterThanOrEqualConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class GreaterThanOrEqualConditionOperator : DisplayConditionOperator + internal class GreaterThanOrEqualConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => Constants.NumberTypes; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanConditionOperator.cs index 244b15c08..72567b9a9 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class LessThanConditionOperator : DisplayConditionOperator + internal class LessThanConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => Constants.NumberTypes; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanOrEqualConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanOrEqualConditionOperator.cs index e47b3f018..fd344dbf3 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanOrEqualConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/LessThanOrEqualConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class LessThanOrEqualConditionOperator : DisplayConditionOperator + internal class LessThanOrEqualConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => Constants.NumberTypes; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/NotEqualConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/NotEqualConditionOperator.cs index a1a9934be..4af94147c 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/NotEqualConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/NotEqualConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class NotEqualConditionOperator : DisplayConditionOperator + internal class NotEqualConditionOperator : ConditionOperator { public override IReadOnlyCollection CompatibleTypes => new List {typeof(object)}; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringContainsConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringContainsConditionOperator.cs index 758e0400e..3ef231cfd 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringContainsConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringContainsConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringContainsConditionOperator : DisplayConditionOperator + internal class StringContainsConditionOperator : ConditionOperator { private readonly MethodInfo _contains; private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEndsWithConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEndsWithConditionOperator.cs index 38ed72633..1903984e9 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEndsWithConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEndsWithConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringEndsWithConditionOperator : DisplayConditionOperator + internal class StringEndsWithConditionOperator : ConditionOperator { private readonly MethodInfo _endsWith; private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEqualsConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEqualsConditionOperator.cs index 91a58ec91..cc0cf432c 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEqualsConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringEqualsConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringEqualsConditionOperator : DisplayConditionOperator + internal class StringEqualsConditionOperator : ConditionOperator { private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotContainsConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotContainsConditionOperator.cs index 671555eb5..97fbac2eb 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotContainsConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotContainsConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringNotContainsConditionOperator : DisplayConditionOperator + internal class StringNotContainsConditionOperator : ConditionOperator { private readonly MethodInfo _contains; private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotEqualConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotEqualConditionOperator.cs index c98d4bef3..33e14b4e1 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotEqualConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNotEqualConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringNotEqualConditionOperator : DisplayConditionOperator + internal class StringNotEqualConditionOperator : ConditionOperator { private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNullConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNullConditionOperator.cs index bb0b99d42..6c51024ed 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNullConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringNullConditionOperator.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; namespace Artemis.Core { - internal class StringNullConditionOperator : DisplayConditionOperator + internal class StringNullConditionOperator : ConditionOperator { public StringNullConditionOperator() { diff --git a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringStartsWithConditionOperator.cs b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringStartsWithConditionOperator.cs index f9f9fbf8e..4b3d9f39b 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Operators/StringStartsWithConditionOperator.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Operators/StringStartsWithConditionOperator.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Artemis.Core { - internal class StringStartsWithConditionOperator : DisplayConditionOperator + internal class StringStartsWithConditionOperator : ConditionOperator { private readonly MethodInfo _startsWith; private readonly MethodInfo _toLower; diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 5671181ca..1436f7bcf 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -42,21 +42,7 @@ namespace Artemis.Core _layerEffects = new List(); _expandedPropertyGroups = new List(); - _expandedPropertyGroups.AddRange(folderEntity.ExpandedPropertyGroups); - - // Load child folders - foreach (var childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId)) - ChildrenList.Add(new Folder(profile, this, childFolder)); - // Load child layers - foreach (var childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId)) - ChildrenList.Add(new Layer(profile, this, childLayer)); - - // Ensure order integrity, should be unnecessary but no one is perfect specially me - ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList(); - for (var index = 0; index < ChildrenList.Count; index++) - ChildrenList[index].Order = index + 1; - - ApplyRenderElementEntity(); + Load(); } internal FolderEntity FolderEntity { get; set; } @@ -263,23 +249,36 @@ namespace Artemis.Core if (!disposing) return; + _disposed = true; + foreach (var baseLayerEffect in LayerEffects) baseLayerEffect.Dispose(); - _layerEffects.Clear(); - foreach (var profileElement in Children) profileElement.Dispose(); - ChildrenList.Clear(); _folderBitmap?.Dispose(); - _folderBitmap = null; - - Profile = null; - _disposed = true; } + internal override void Load() + { + _expandedPropertyGroups.AddRange(FolderEntity.ExpandedPropertyGroups); - internal override void ApplyToEntity() + // Load child folders + foreach (var childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId)) + ChildrenList.Add(new Folder(Profile, this, childFolder)); + // Load child layers + foreach (var childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId)) + ChildrenList.Add(new Layer(Profile, this, childLayer)); + + // Ensure order integrity, should be unnecessary but no one is perfect specially me + ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList(); + for (var index = 0; index < ChildrenList.Count; index++) + ChildrenList[index].Order = index + 1; + + LoadRenderElement(); + } + + internal override void Save() { if (_disposed) throw new ObjectDisposedException("Folder"); @@ -295,11 +294,11 @@ namespace Artemis.Core FolderEntity.ExpandedPropertyGroups.Clear(); FolderEntity.ExpandedPropertyGroups.AddRange(_expandedPropertyGroups); - ApplyRenderElementToEntity(); - // Conditions RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.Entity; DisplayConditionGroup?.ApplyToEntity(); + + SaveRenderElement(); } #region Events diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 5470a4c46..b1d411e9c 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -4,7 +4,6 @@ using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.LayerBrushes; using Artemis.Core.LayerEffects; -using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; using Artemis.Storage.Entities.Profile.Abstract; using SkiaSharp; @@ -41,30 +40,27 @@ namespace Artemis.Core _leds = new List(); _expandedPropertyGroups = new List(); - General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized; + InitializeDefaultGroups(); + + parent.AddChild(this); ApplyRenderElementDefaults(); } internal Layer(Profile profile, ProfileElement parent, LayerEntity layerEntity) { LayerEntity = layerEntity; - EntityId = layerEntity.Id; - Profile = profile; Parent = parent; - Name = layerEntity.Name; - Enabled = layerEntity.Enabled; - Order = layerEntity.Order; General = new LayerGeneralProperties(); Transform = new LayerTransformProperties(); _layerEffects = new List(); _leds = new List(); _expandedPropertyGroups = new List(); - _expandedPropertyGroups.AddRange(layerEntity.ExpandedPropertyGroups); - General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized; - ApplyRenderElementEntity(); + InitializeDefaultGroups(); + + Load(); } internal LayerEntity LayerEntity { get; set; } @@ -128,25 +124,41 @@ namespace Artemis.Core // Brush first in case it depends on any of the other disposables during it's own disposal _layerBrush?.Dispose(); - _layerBrush = null; foreach (var baseLayerEffect in LayerEffects) baseLayerEffect.Dispose(); - _layerEffects.Clear(); _general?.Dispose(); - _general = null; _layerBitmap?.Dispose(); - _layerBitmap = null; _transform?.Dispose(); - _transform = null; + } - Profile = null; + private void InitializeDefaultGroups() + { + // Layers have two hardcoded property groups, instantiate them + General.Initialize(this, "General.", Constants.CorePluginInfo); + Transform.Initialize(this, "Transform.", Constants.CorePluginInfo); + + General.ShapeType.BaseValueChanged += ShapeTypeOnBaseValueChanged; + ApplyShapeType(); } #region Storage - internal override void ApplyToEntity() + internal override void Load() + { + EntityId = LayerEntity.Id; + Name = LayerEntity.Name; + Enabled = LayerEntity.Enabled; + Order = LayerEntity.Order; + + _expandedPropertyGroups.AddRange(LayerEntity.ExpandedPropertyGroups); + ActivateLayerBrush(); + + LoadRenderElement(); + } + + internal override void Save() { if (_disposed) throw new ObjectDisposedException("Layer"); @@ -181,20 +193,13 @@ namespace Artemis.Core RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.Entity; DisplayConditionGroup?.ApplyToEntity(); - ApplyRenderElementToEntity(); + SaveRenderElement(); } #endregion #region Shape management - private void GeneralOnPropertyGroupInitialized(object sender, EventArgs e) - { - ApplyShapeType(); - General.ShapeType.BaseValueChanged -= ShapeTypeOnBaseValueChanged; - General.ShapeType.BaseValueChanged += ShapeTypeOnBaseValueChanged; - } - private void ShapeTypeOnBaseValueChanged(object sender, EventArgs e) { ApplyShapeType(); @@ -290,7 +295,7 @@ namespace Artemis.Core baseLayerEffect.Update(delta); } } - + /// public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo) { @@ -646,7 +651,51 @@ namespace Artemis.Core #endregion - #region Activation + #region Brush management + + /// + /// Changes the current layer brush to the brush described in the provided + /// + public void ChangeLayerBrush(LayerBrushDescriptor descriptor) + { + if (descriptor == null) + throw new ArgumentNullException(nameof(descriptor)); + + // Ensure the brush reference matches the brush + var current = General.BrushReference.CurrentValue; + if (current.BrushPluginGuid != descriptor.LayerBrushProvider.PluginInfo.Guid || current.BrushType != descriptor.LayerBrushType.Name) + { + General.BrushReference.CurrentValue = new LayerBrushReference + { + BrushPluginGuid = descriptor.LayerBrushProvider.PluginInfo.Guid, + BrushType = descriptor.LayerBrushType.Name + }; + } + + ActivateLayerBrush(); + } + + /// + /// Removes the current layer brush from the layer + /// + public void RemoveLayerBrush() + { + if (LayerBrush == null) + return; + + var brush = LayerBrush; + DeactivateLayerBrush(); + LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush.")); + } + + internal void ActivateLayerBrush() + { + var current = General.BrushReference.CurrentValue; + var descriptor = LayerBrushStore.Get(current.BrushPluginGuid, current.BrushType)?.LayerBrushDescriptor; + descriptor?.CreateInstance(this); + + OnLayerBrushUpdated(); + } internal void DeactivateLayerBrush() { @@ -656,16 +705,8 @@ namespace Artemis.Core var brush = LayerBrush; LayerBrush = null; brush.Dispose(); - } - internal void RemoveLayerBrush() - { - if (LayerBrush == null) - return; - - var brush = LayerBrush; - DeactivateLayerBrush(); - LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush.")); + OnLayerBrushUpdated(); } #endregion diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index e753cd3d7..b6720b92f 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -171,14 +171,6 @@ namespace Artemis.Core OnPropertyGroupInitialized(); } - internal void InitializeDataBindings(IDataModelService dataModelService, IDataModelService dataModelService1) - { - foreach (var layerProperty in LayerProperties) - { - layerProperty.InitializeDataBindings(dataModelService); - } - } - internal void ApplyToEntity() { if (!PropertiesInitialized) diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index 030cf786f..e23874cfe 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -22,7 +22,7 @@ namespace Artemis.Core RedoStack = new Stack(); AddChild(new Folder(this, this, "Root folder")); - ApplyToEntity(); + Save(); } internal Profile(ProfileModule module, ProfileEntity profileEntity) @@ -129,7 +129,7 @@ namespace Artemis.Core _disposed = true; } - internal override void ApplyToEntity() + internal override void Save() { if (_disposed) throw new ObjectDisposedException("Profile"); @@ -140,7 +140,7 @@ namespace Artemis.Core ProfileEntity.IsActive = IsActivated; foreach (var profileElement in Children) - profileElement.ApplyToEntity(); + profileElement.Save(); ProfileEntity.Folders.Clear(); ProfileEntity.Folders.AddRange(GetAllFolders().Select(f => f.FolderEntity)); diff --git a/src/Artemis.Core/Models/Profile/ProfileElement.cs b/src/Artemis.Core/Models/Profile/ProfileElement.cs index efa5bdb52..0a2ee39aa 100644 --- a/src/Artemis.Core/Models/Profile/ProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/ProfileElement.cs @@ -23,18 +23,27 @@ namespace Artemis.Core ChildrenList = new List(); } + /// + /// Gets the unique ID of this profile element + /// public Guid EntityId { get => _entityId; internal set => SetAndNotify(ref _entityId, value); } + /// + /// Gets the profile this element belongs to + /// public Profile Profile { get => _profile; internal set => SetAndNotify(ref _profile, value); } + /// + /// Gets the parent of this element + /// public ProfileElement Parent { get => _parent; @@ -73,12 +82,6 @@ namespace Artemis.Core set => SetAndNotify(ref _enabled, value); } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - /// /// Updates the element /// @@ -90,39 +93,13 @@ namespace Artemis.Core /// public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo); - public List GetAllFolders() + /// + public override string ToString() { - if (_disposed) - throw new ObjectDisposedException(GetType().Name); - - var folders = new List(); - foreach (var childFolder in Children.Where(c => c is Folder).Cast()) - { - // Add all folders in this element - folders.Add(childFolder); - // Add all folders in folders inside this element - folders.AddRange(childFolder.GetAllFolders()); - } - - return folders; + return $"{nameof(EntityId)}: {EntityId}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}"; } - public List GetAllLayers() - { - if (_disposed) - throw new ObjectDisposedException(GetType().Name); - - var layers = new List(); - - // Add all layers in this element - layers.AddRange(Children.Where(c => c is Layer).Cast()); - - // Add all layers in folders inside this element - foreach (var childFolder in Children.Where(c => c is Folder).Cast()) - layers.AddRange(childFolder.GetAllLayers()); - - return layers; - } + #region Hierarchy /// /// Adds a profile element to the collection, optionally at the given position (1-based) @@ -189,9 +166,64 @@ namespace Artemis.Core OnChildRemoved(); } - public override string ToString() + /// + /// Returns a flattened list of all child folders + /// + /// + public List GetAllFolders() { - return $"{nameof(EntityId)}: {EntityId}, {nameof(Order)}: {Order}, {nameof(Name)}: {Name}"; + if (_disposed) + throw new ObjectDisposedException(GetType().Name); + + var folders = new List(); + foreach (var childFolder in Children.Where(c => c is Folder).Cast()) + { + // Add all folders in this element + folders.Add(childFolder); + // Add all folders in folders inside this element + folders.AddRange(childFolder.GetAllFolders()); + } + + return folders; + } + + /// + /// Returns a flattened list of all child layers + /// + /// + public List GetAllLayers() + { + if (_disposed) + throw new ObjectDisposedException(GetType().Name); + + var layers = new List(); + + // Add all layers in this element + layers.AddRange(Children.Where(c => c is Layer).Cast()); + + // Add all layers in folders inside this element + foreach (var childFolder in Children.Where(c => c is Folder).Cast()) + layers.AddRange(childFolder.GetAllLayers()); + + return layers; + } + + #endregion + + #region Storage + + internal abstract void Load(); + internal abstract void Save(); + + #endregion + + #region IDisposable + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) @@ -201,10 +233,7 @@ namespace Artemis.Core } } - /// - /// Applies the profile element's properties to the underlying storage entity - /// - internal abstract void ApplyToEntity(); + #endregion #region Events diff --git a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs index a75ed2b56..bc3d86cb6 100644 --- a/src/Artemis.Core/Models/Profile/RenderProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -12,21 +12,23 @@ namespace Artemis.Core { public abstract class RenderProfileElement : ProfileElement { - protected void ApplyRenderElementDefaults() + internal void ApplyRenderElementDefaults() { MainSegmentLength = TimeSpan.FromSeconds(5); } - protected void ApplyRenderElementEntity() + internal void LoadRenderElement() { StartSegmentLength = RenderElementEntity.StartSegmentLength; MainSegmentLength = RenderElementEntity.MainSegmentLength; EndSegmentLength = RenderElementEntity.EndSegmentLength; DisplayContinuously = RenderElementEntity.DisplayContinuously; AlwaysFinishTimeline = RenderElementEntity.AlwaysFinishTimeline; + + ActivateEffects(); } - protected void ApplyRenderElementToEntity() + internal void SaveRenderElement() { RenderElementEntity.StartSegmentLength = StartSegmentLength; RenderElementEntity.MainSegmentLength = MainSegmentLength; @@ -206,7 +208,7 @@ namespace Artemis.Core #endregion - #region Effects + #region Effect management protected List _layerEffects; @@ -215,11 +217,35 @@ namespace Artemis.Core /// public ReadOnlyCollection LayerEffects => _layerEffects.AsReadOnly(); - internal void RemoveLayerEffect([NotNull] BaseLayerEffect effect) + /// + /// Adds a the layer effect described inthe provided + /// + public void AddLayerEffect(LayerEffectDescriptor descriptor) + { + if (descriptor == null) + throw new ArgumentNullException(nameof(descriptor)); + + var entity = new LayerEffectEntity + { + Id = Guid.NewGuid(), + Enabled = true, + Order = LayerEffects.Count + 1 + }; + descriptor.CreateInstance(this, entity); + OnLayerEffectsUpdated(); + } + + /// + /// Removes the provided layer + /// + /// + public void RemoveLayerEffect([NotNull] BaseLayerEffect effect) { if (effect == null) throw new ArgumentNullException(nameof(effect)); - DeactivateLayerEffect(effect); + // Remove the effect from the layer and dispose it + _layerEffects.Remove(effect); + effect.Dispose(); // Update the order on the remaining effects var index = 0; @@ -232,20 +258,31 @@ namespace Artemis.Core OnLayerEffectsUpdated(); } - internal void AddLayerEffect([NotNull] BaseLayerEffect effect) + internal void ActivateEffects() { - if (effect == null) throw new ArgumentNullException(nameof(effect)); - _layerEffects.Add(effect); - OnLayerEffectsUpdated(); + foreach (var layerEffectEntity in RenderElementEntity.LayerEffects) + { + if (_layerEffects.Any(e => e.EntityId == layerEffectEntity.Id)) + continue; + + var descriptor = LayerEffectStore.Get(layerEffectEntity.PluginGuid, layerEffectEntity.EffectType)?.LayerEffectDescriptor; + descriptor?.CreateInstance(this, layerEffectEntity); + } } - internal void DeactivateLayerEffect([NotNull] BaseLayerEffect effect) + internal void ActivateLayerEffect(BaseLayerEffect layerEffect) { - if (effect == null) throw new ArgumentNullException(nameof(effect)); + _layerEffects.Add(layerEffect); - // Remove the effect from the layer and dispose it - _layerEffects.Remove(effect); - effect.Dispose(); + // Update the order on the effects + var index = 0; + foreach (var baseLayerEffect in LayerEffects.OrderBy(e => e.Order)) + { + baseLayerEffect.Order = Order = index + 1; + index++; + } + + OnLayerEffectsUpdated(); } #endregion @@ -296,6 +333,5 @@ namespace Artemis.Core } #endregion - } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs index 9edd2a6cc..e0fbc4f35 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs @@ -22,6 +22,12 @@ namespace Artemis.Core.DataModelExpansions [DataModelIgnore] public DataModelPropertyAttribute DataModelDescription { get; internal set; } + /// + /// Gets the is expansion status indicating whether this data model expands the main data model + /// + [DataModelIgnore] + public bool IsExpansion { get; internal set; } + public bool ContainsPath(string path) { var parts = path.Split('.'); diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs index 8230e08f8..28946a89b 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModelExpansion.cs @@ -10,7 +10,8 @@ namespace Artemis.Core.DataModelExpansions public abstract class DataModelExpansion : BaseDataModelExpansion where T : DataModel { /// - /// The data model driving this module + /// The main data model of this data model expansion + /// Note: This default data model is automatically registered upon plugin enable /// public T DataModel { diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs index 685435646..a4173e75c 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs @@ -1,4 +1,5 @@ using System; +using Ninject; namespace Artemis.Core.LayerBrushes { @@ -41,5 +42,28 @@ namespace Artemis.Core.LayerBrushes /// The plugin that provided this /// public LayerBrushProvider LayerBrushProvider { get; } + + /// + /// Gets or sets the kernel used to instantiate the described layer brush + /// + internal IKernel Kernel { get; set; } + + /// + /// Creates an instance of the described brush and applies it to the layer + /// + internal void CreateInstance(Layer layer) + { + if (layer.LayerBrush != null) + throw new ArtemisCoreException("Layer already has an instantiated layer brush"); + + var brush = (BaseLayerBrush) Kernel.Get(LayerBrushType); + brush.Layer = layer; + brush.Descriptor = this; + brush.Initialize(); + brush.Update(0); + + layer.LayerBrush = brush; + layer.OnLayerBrushUpdated(); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs index b3c1db3b5..47d95d396 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs @@ -1,4 +1,8 @@ using System; +using System.Linq; +using Artemis.Core.LayerBrushes; +using Artemis.Storage.Entities.Profile; +using Ninject; namespace Artemis.Core.LayerEffects { @@ -41,5 +45,33 @@ namespace Artemis.Core.LayerEffects /// The plugin that provided this /// public LayerEffectProvider LayerEffectProvider { get; } + + /// + /// Gets or sets the kernel used to instantiate the described layer effect + /// + internal IKernel Kernel { get; set; } + + /// + /// Creates an instance of the described effect and applies it to the render element + /// + internal void CreateInstance(RenderProfileElement renderElement, LayerEffectEntity entity) + { + // Skip effects already on the element + if (renderElement.LayerEffects.Any(e => e.EntityId == entity.Id)) + return; + + var effect = (BaseLayerEffect) Kernel.Get(LayerEffectType); + effect.ProfileElement = renderElement; + effect.EntityId = entity.Id; + effect.Order = entity.Order; + effect.Name = entity.Name; + effect.Enabled = entity.Enabled; + effect.Descriptor = this; + + effect.Initialize(); + effect.Update(0); + + renderElement.ActivateLayerEffect(effect); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs index 31efee688..e67eb1174 100644 --- a/src/Artemis.Core/Plugins/Modules/Module.cs +++ b/src/Artemis.Core/Plugins/Modules/Module.cs @@ -14,6 +14,7 @@ namespace Artemis.Core.Modules { /// /// The data model driving this module + /// Note: This default data model is automatically registered upon plugin enable /// public T DataModel { diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs index 9b7c303ff..86afbcc0a 100644 --- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs +++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs @@ -18,6 +18,7 @@ namespace Artemis.Core.Modules { /// /// The data model driving this module + /// Note: This default data model is automatically registered upon plugin enable /// public T DataModel { @@ -118,7 +119,7 @@ namespace Artemis.Core.Modules /// Indicates whether or not a profile change is being animated /// public bool AnimatingProfileChange { get; private set; } - + /// /// Called after the profile has updated /// diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 1c739c425..eaf195c28 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -9,6 +9,7 @@ using Artemis.Core.JsonConverters; using Artemis.Core.Ninject; using Artemis.Storage; using Newtonsoft.Json; +using Ninject; using RGB.NET.Core; using Serilog; using Serilog.Events; @@ -23,6 +24,7 @@ namespace Artemis.Core.Services internal class CoreService : ICoreService { private readonly Stopwatch _frameStopWatch; + private readonly IKernel _kernel; private readonly ILogger _logger; private readonly PluginSetting _loggingLevel; private readonly IPluginService _pluginService; @@ -34,9 +36,10 @@ namespace Artemis.Core.Services private List _modules; // ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else - public CoreService(ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService, - IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService) + public CoreService(IKernel kernel, ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService, + IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService) { + _kernel = kernel; _logger = logger; _pluginService = pluginService; _rgbService = rgbService; @@ -77,6 +80,8 @@ namespace Artemis.Core.Services _logger.Information("Initializing Artemis Core version {version}", versionAttribute?.InformationalVersion); ApplyLoggingLevel(); + DeserializationLogger.Initialize(_kernel); + // Initialize the services _pluginService.CopyBuiltInPlugins(); _pluginService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock")); diff --git a/src/Artemis.Core/Services/DataBindingService.cs b/src/Artemis.Core/Services/DataBindingService.cs deleted file mode 100644 index 3af46569f..000000000 --- a/src/Artemis.Core/Services/DataBindingService.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; -using Serilog; - -namespace Artemis.Core.Services -{ - internal class DataBindingService : IDataBindingService - { - private readonly ILogger _logger; - private readonly List _registeredDataBindingModifierTypes; - - public DataBindingService(ILogger logger) - { - _logger = logger; - _registeredDataBindingModifierTypes = new List(); - - RegisterBuiltInModifiers(); - } - - public IReadOnlyCollection RegisteredDataBindingModifierTypes - { - get - { - lock (_registeredDataBindingModifierTypes) - { - return _registeredDataBindingModifierTypes.AsReadOnly(); - } - } - } - - public void RegisterModifierType(PluginInfo pluginInfo, DataBindingModifierType dataBindingModifierType) - { - if (pluginInfo == null) - throw new ArgumentNullException(nameof(pluginInfo)); - if (dataBindingModifierType == null) - throw new ArgumentNullException(nameof(dataBindingModifierType)); - - lock (_registeredDataBindingModifierTypes) - { - if (_registeredDataBindingModifierTypes.Contains(dataBindingModifierType)) - return; - - dataBindingModifierType.Register(pluginInfo, this); - _registeredDataBindingModifierTypes.Add(dataBindingModifierType); - } - } - - public void RemoveModifierType(DataBindingModifierType dataBindingModifierType) - { - if (dataBindingModifierType == null) - throw new ArgumentNullException(nameof(dataBindingModifierType)); - - lock (_registeredDataBindingModifierTypes) - { - if (!_registeredDataBindingModifierTypes.Contains(dataBindingModifierType)) - return; - - dataBindingModifierType.Unsubscribe(); - _registeredDataBindingModifierTypes.Remove(dataBindingModifierType); - } - } - - public List GetCompatibleModifierTypes(Type type) - { - lock (_registeredDataBindingModifierTypes) - { - if (type == null) - return new List(_registeredDataBindingModifierTypes); - - var candidates = _registeredDataBindingModifierTypes.Where(c => c.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList(); - - // If there are multiple modifier types with the same description, use the closest match - foreach (var dataBindingModifierTypes in candidates.GroupBy(c => c.Description).Where(g => g.Count() > 1).ToList()) - { - var bestCandidate = dataBindingModifierTypes.OrderByDescending(c => c.CompatibleTypes.Contains(type)).FirstOrDefault(); - foreach (var dataBindingModifierType in dataBindingModifierTypes) - { - if (dataBindingModifierType != bestCandidate) - candidates.Remove(dataBindingModifierType); - } - } - - return candidates; - } - } - - public DataBindingModifierType GetModifierType(Guid modifierTypePluginGuid, string modifierType) - { - return RegisteredDataBindingModifierTypes.FirstOrDefault(o => o.PluginInfo.Guid == modifierTypePluginGuid && o.GetType().Name == modifierType); - } - - public void LogModifierDeserializationFailure(string modifierName, JsonSerializationException exception) - { - _logger.Warning(exception, "Failed to deserialize static parameter for modifier {modifierName}", modifierName); - } - - private void RegisterBuiltInModifiers() - { - RegisterModifierType(Constants.CorePluginInfo, new MultiplicationModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new DivideModifierType()); - RegisterModifierType(Constants.CorePluginInfo, new FloorModifierType()); - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/DataModelService.cs b/src/Artemis.Core/Services/DataModelService.cs deleted file mode 100644 index 8d5d8956d..000000000 --- a/src/Artemis.Core/Services/DataModelService.cs +++ /dev/null @@ -1,252 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Artemis.Core.DataModelExpansions; -using Artemis.Core.Modules; -using Newtonsoft.Json; -using Serilog; - -namespace Artemis.Core.Services -{ - /// - /// Provides access to the main data model - /// - internal class DataModelService : IDataModelService - { - private readonly List _dataModelExpansions; - private readonly ILogger _logger; - private readonly IPluginService _pluginService; - private readonly List _registeredConditionOperators; - - public DataModelService(IPluginService pluginService, ILogger logger) - { - _pluginService = pluginService; - _logger = logger; - _dataModelExpansions = new List(); - _registeredConditionOperators = new List(); - - _pluginService.PluginEnabled += PluginServiceOnPluginEnabled; - _pluginService.PluginDisabled += PluginServiceOnPluginDisabled; - - RegisterBuiltInConditionOperators(); - - foreach (var module in _pluginService.GetPluginsOfType().Where(m => m.InternalExpandsMainDataModel)) - AddModuleDataModel(module); - foreach (var dataModelExpansion in _pluginService.GetPluginsOfType()) - AddDataModelExpansionDataModel(dataModelExpansion); - } - - public IReadOnlyCollection RegisteredConditionOperators - { - get - { - lock (_registeredConditionOperators) - { - return _registeredConditionOperators.AsReadOnly(); - } - } - } - - public IReadOnlyCollection DataModelExpansions - { - get - { - lock (_dataModelExpansions) - { - return new List(_dataModelExpansions).AsReadOnly(); - } - } - } - - public void AddExpansion(DataModel dataModelExpansion) - { - lock (_dataModelExpansions) - { - _dataModelExpansions.Add(dataModelExpansion); - // TODO SpoinkyNL 3-3-2018: Initialize the expansion and fire an event - } - } - - public void RemoveExpansion(DataModel dataModelExpansion) - { - lock (_dataModelExpansions) - { - if (!_dataModelExpansions.Contains(dataModelExpansion)) - throw new ArtemisCoreException("Cannot remove a data model expansion that wasn't previously added."); - - // TODO SpoinkyNL 3-3-2018: Dispose the expansion and fire an event - _dataModelExpansions.Remove(dataModelExpansion); - } - } - - public DataModel GetPluginDataModel(Plugin plugin) - { - if (plugin is Module module) - return module.InternalDataModel; - if (plugin is BaseDataModelExpansion dataModelExpansion) - return dataModelExpansion.InternalDataModel; - return null; - } - - public DataModel GetPluginDataModelByGuid(Guid pluginGuid) - { - var pluginInfo = _pluginService.GetAllPluginInfo().FirstOrDefault(i => i.Guid == pluginGuid); - if (pluginInfo == null || !pluginInfo.Enabled) - return null; - - return GetPluginDataModel(pluginInfo.Instance); - } - - public bool GetPluginExtendsDataModel(Plugin plugin) - { - if (plugin is Module module) - return module.InternalExpandsMainDataModel; - if (plugin is BaseDataModelExpansion) - return true; - - return false; - } - - - public void RegisterConditionOperator(PluginInfo pluginInfo, DisplayConditionOperator displayConditionOperator) - { - if (pluginInfo == null) - throw new ArgumentNullException(nameof(pluginInfo)); - if (displayConditionOperator == null) - throw new ArgumentNullException(nameof(displayConditionOperator)); - - lock (_registeredConditionOperators) - { - if (_registeredConditionOperators.Contains(displayConditionOperator)) - return; - - displayConditionOperator.Register(pluginInfo, this); - _registeredConditionOperators.Add(displayConditionOperator); - } - } - - public void RemoveConditionOperator(DisplayConditionOperator displayConditionOperator) - { - if (displayConditionOperator == null) - throw new ArgumentNullException(nameof(displayConditionOperator)); - - lock (_registeredConditionOperators) - { - if (!_registeredConditionOperators.Contains(displayConditionOperator)) - return; - - displayConditionOperator.Unsubscribe(); - _registeredConditionOperators.Remove(displayConditionOperator); - } - } - - public List GetCompatibleConditionOperators(Type type) - { - lock (_registeredConditionOperators) - { - if (type == null) - return new List(_registeredConditionOperators); - - var candidates = _registeredConditionOperators.Where(c => c.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList(); - - // If there are multiple operators with the same description, use the closest match - foreach (var displayConditionOperators in candidates.GroupBy(c => c.Description).Where(g => g.Count() > 1).ToList()) - { - var bestCandidate = displayConditionOperators.OrderByDescending(c => c.CompatibleTypes.Contains(type)).FirstOrDefault(); - foreach (var displayConditionOperator in displayConditionOperators) - { - if (displayConditionOperator != bestCandidate) - candidates.Remove(displayConditionOperator); - } - } - - return candidates; - } - } - - public DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType) - { - return RegisteredConditionOperators.FirstOrDefault(o => o.PluginInfo.Guid == operatorPluginGuid && o.GetType().Name == operatorType); - } - - public void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception) - { - _logger.Warning( - exception, - "Failed to deserialize display condition predicate {left} {operator} {right}", - displayConditionPredicate.Entity.LeftPropertyPath, - displayConditionPredicate.Entity.OperatorType, - displayConditionPredicate.Entity.RightPropertyPath - ); - } - - public void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionPredicate, JsonException exception) - { - _logger.Warning( - exception, - "Failed to deserialize display condition list predicate {list} => {left} {operator} {right}", - displayConditionPredicate.Entity.ListPropertyPath, - displayConditionPredicate.Entity.LeftPropertyPath, - displayConditionPredicate.Entity.OperatorType, - displayConditionPredicate.Entity.RightPropertyPath - ); - } - - private void RegisterBuiltInConditionOperators() - { - // General usage for any type - RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator()); - - // Numeric operators - RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator()); - - // String operators - RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator()); - RegisterConditionOperator(Constants.CorePluginInfo, new StringNullConditionOperator()); - } - - private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) - { - if (e.PluginInfo.Instance is Module module && module.InternalExpandsMainDataModel) - AddModuleDataModel(module); - else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion) - AddDataModelExpansionDataModel(dataModelExpansion); - } - - private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion) - { - if (dataModelExpansion.InternalDataModel.DataModelDescription == null) - throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null"); - - AddExpansion(dataModelExpansion.InternalDataModel); - } - - private void AddModuleDataModel(Module module) - { - if (module.InternalDataModel.DataModelDescription == null) - throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null"); - - AddExpansion(module.InternalDataModel); - } - - private void PluginServiceOnPluginDisabled(object sender, PluginEventArgs e) - { - // Remove all data models related to the plugin - lock (_dataModelExpansions) - { - var toRemove = _dataModelExpansions.Where(d => d.PluginInfo == e.PluginInfo).ToList(); - foreach (var dataModel in toRemove) - _dataModelExpansions.Remove(dataModel); - } - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs index 674db94ef..b506f18ac 100644 --- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs +++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; namespace Artemis.Core.Services { + /// + /// A service that initializes the Core and manages the render loop + /// public interface ICoreService : IArtemisService, IDisposable { /// diff --git a/src/Artemis.Core/Services/Interfaces/IDataModelService.cs b/src/Artemis.Core/Services/Interfaces/IDataModelService.cs deleted file mode 100644 index 7b2cb5582..000000000 --- a/src/Artemis.Core/Services/Interfaces/IDataModelService.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using Artemis.Core.DataModelExpansions; -using Artemis.Core.Properties; -using Newtonsoft.Json; - -namespace Artemis.Core.Services -{ - public interface IDataModelService : IArtemisService - { - /// - /// Gets a read-only collection of all registered condition operators - /// - IReadOnlyCollection RegisteredConditionOperators { get; } - - /// - /// Gets a read-only collection of all registered data model expansions - /// - IReadOnlyCollection DataModelExpansions { get; } - - /// - /// Add an expansion to the datamodel to be available for use after the next update - /// - /// - void AddExpansion(DataModel baseDataModelExpansion); - - /// - /// Remove a previously added expansion so that it is no longer available and updated - /// - /// - void RemoveExpansion(DataModel baseDataModelExpansion); - - /// - /// If found, returns the data model of the provided plugin - /// - /// Should be a module with a data model or a data model expansion - DataModel GetPluginDataModel(Plugin plugin); - - /// - /// If found, returns the data model of the provided plugin - /// - /// Should be a module with a data model or a data model expansion - DataModel GetPluginDataModelByGuid(Guid pluginGuid); - - /// - /// Determines whether the given plugin expands the main data model - /// - /// - /// - bool GetPluginExtendsDataModel(Plugin plugin); - - /// - /// Registers a new condition operator for use in layer conditions - /// - /// The PluginInfo of the plugin this condition operator belongs to - /// The condition operator to register - void RegisterConditionOperator([NotNull] PluginInfo pluginInfo, [NotNull] DisplayConditionOperator displayConditionOperator); - - /// - /// Removes a condition operator so it is no longer available for use in layer conditions - /// - /// The layer condition operator to remove - void RemoveConditionOperator([NotNull] DisplayConditionOperator displayConditionOperator); - - /// - /// Returns all the display condition operators compatible with the provided type - /// - List GetCompatibleConditionOperators(Type type); - - /// - /// Gets a condition operator by its plugin GUID and type name - /// - /// The operator's plugin GUID - /// The type name of the operator - DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType); - - /// - /// Logs a predicate deserialization failure - /// - /// The predicate that failed to deserialize - /// The JSON exception that occurred - void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception); - - /// - /// Logs a list predicate deserialization failure - /// - /// The list predicate that failed to deserialize - /// The JSON exception that occurred - void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionListPredicate, JsonException exception); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/IDeviceService.cs b/src/Artemis.Core/Services/Interfaces/IDeviceService.cs index cb09e83e7..154ad5466 100644 --- a/src/Artemis.Core/Services/Interfaces/IDeviceService.cs +++ b/src/Artemis.Core/Services/Interfaces/IDeviceService.cs @@ -1,5 +1,8 @@ namespace Artemis.Core.Services { + /// + /// A service that allows you manage an + /// public interface IDeviceService : IArtemisService { /// diff --git a/src/Artemis.Core/Services/Interfaces/IRenderElementService.cs b/src/Artemis.Core/Services/Interfaces/IRenderElementService.cs deleted file mode 100644 index 79319f578..000000000 --- a/src/Artemis.Core/Services/Interfaces/IRenderElementService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Artemis.Core.LayerBrushes; -using Artemis.Core.LayerEffects; - -namespace Artemis.Core.Services -{ - public interface IRenderElementService : IArtemisService - { - /// - /// Creates a new layer - /// - /// - /// - /// - /// - Layer CreateLayer(Profile profile, ProfileElement parent, string name); - - /// - /// Removes the currently active layer brush from the and deletes any settings - /// - /// The layer to remove the active brush from - void RemoveLayerBrush(Layer layer); - - /// - /// Deactivates the currently active layer brush from the but keeps all settings - /// - /// The layer to deactivate the active brush on - void DeactivateLayerBrush(Layer layer); - - /// - /// Instantiates and adds the described by the provided - /// - /// to the . - /// - /// The layer to instantiate the brush for - /// - BaseLayerBrush InstantiateLayerBrush(Layer layer); - - /// - /// Instantiates and adds the described by the provided - /// to the . - /// - /// The layer/folder to instantiate the effect for - void InstantiateLayerEffects(RenderProfileElement renderProfileElement); - - /// - /// Adds the described by the provided to the - /// . - /// - /// The layer/folder to instantiate the effect for - /// - /// - BaseLayerEffect AddLayerEffect(RenderProfileElement renderProfileElement, LayerEffectDescriptor layerEffectDescriptor); - - void RemoveLayerEffect(BaseLayerEffect layerEffect); - - void InstantiateDisplayConditions(RenderProfileElement renderElement); - void InstantiateDataBindings(RenderProfileElement renderElement); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs index 5b78f6bfb..e5cd0c213 100644 --- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs +++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs @@ -4,7 +4,10 @@ using RGB.NET.Core; namespace Artemis.Core.Services { - public interface IRgbService : IArtemisService + /// + /// A service that allows you to manage the and its contents + /// + public interface IRgbService : IArtemisService, IDisposable { /// /// Gets or sets the RGB surface rendering is performed on @@ -26,7 +29,14 @@ namespace Artemis.Core.Services /// IReadOnlyCollection LoadedDevices { get; } + /// + /// Gets the update trigger that drives the render loop + /// TimerUpdateTrigger UpdateTrigger { get; } + + /// + /// Gets or sets whether rendering should be paused + /// bool IsRenderPaused { get; set; } /// @@ -35,8 +45,6 @@ namespace Artemis.Core.Services /// void AddDeviceProvider(IRGBDeviceProvider deviceProvider); - void Dispose(); - /// /// Occurs when a single device has loaded /// @@ -47,6 +55,9 @@ namespace Artemis.Core.Services /// event EventHandler DeviceReloaded; + /// + /// Recalculates the LED group used by the + /// void UpdateSurfaceLedGroup(); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs b/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs new file mode 100644 index 000000000..9ea6fab80 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/ConditionOperatorService.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Core.Services +{ + internal class ConditionOperatorService : IConditionOperatorService + { + public ConditionOperatorService() + { + RegisterBuiltInConditionOperators(); + } + + public ConditionOperatorRegistration RegisterConditionOperator(PluginInfo pluginInfo, ConditionOperator conditionOperator) + { + if (pluginInfo == null) + throw new ArgumentNullException(nameof(pluginInfo)); + if (conditionOperator == null) + throw new ArgumentNullException(nameof(conditionOperator)); + + conditionOperator.PluginInfo = pluginInfo; + return ConditionOperatorStore.Add(conditionOperator); + } + + public void RemoveConditionOperator(ConditionOperatorRegistration registration) + { + if (registration == null) + throw new ArgumentNullException(nameof(registration)); + ConditionOperatorStore.Remove(registration); + } + + public List GetConditionOperatorsForType(Type type) + { + return ConditionOperatorStore.GetForType(type).Select(r => r.ConditionOperator).ToList(); + } + + public ConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType) + { + return ConditionOperatorStore.Get(operatorPluginGuid, operatorType)?.ConditionOperator; + } + + private void RegisterBuiltInConditionOperators() + { + // General usage for any type + RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator()); + + // Numeric operators + RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator()); + + // String operators + RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator()); + RegisterConditionOperator(Constants.CorePluginInfo, new StringNullConditionOperator()); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/DataBindingService.cs b/src/Artemis.Core/Services/Registration/DataBindingService.cs new file mode 100644 index 000000000..8deed0c63 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/DataBindingService.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Core.Services +{ + internal class DataBindingService : IDataBindingService + { + public DataBindingService() + { + RegisterBuiltInModifiers(); + } + + public DataBindingModifierTypeRegistration RegisterModifierType(PluginInfo pluginInfo, DataBindingModifierType dataBindingModifierType) + { + if (pluginInfo == null) + throw new ArgumentNullException(nameof(pluginInfo)); + if (dataBindingModifierType == null) + throw new ArgumentNullException(nameof(dataBindingModifierType)); + + dataBindingModifierType.PluginInfo = pluginInfo; + return DataBindingModifierTypeStore.Add(dataBindingModifierType); + } + + public void RemoveModifierType(DataBindingModifierTypeRegistration registration) + { + if (registration == null) + throw new ArgumentNullException(nameof(registration)); + DataBindingModifierTypeStore.Remove(registration); + } + + public List GetCompatibleModifierTypes(Type type) + { + return DataBindingModifierTypeStore.GetForType(type).Select(r => r.DataBindingModifierType).ToList(); + } + + public DataBindingModifierType GetModifierType(Guid modifierTypePluginGuid, string modifierType) + { + return DataBindingModifierTypeStore.Get(modifierTypePluginGuid, modifierType)?.DataBindingModifierType; + } + + private void RegisterBuiltInModifiers() + { + RegisterModifierType(Constants.CorePluginInfo, new MultiplicationModifierType()); + RegisterModifierType(Constants.CorePluginInfo, new DivideModifierType()); + RegisterModifierType(Constants.CorePluginInfo, new FloorModifierType()); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/DataModelService.cs b/src/Artemis.Core/Services/Registration/DataModelService.cs new file mode 100644 index 000000000..f3dcfaeb9 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/DataModelService.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.DataModelExpansions; +using Artemis.Core.Modules; + +namespace Artemis.Core.Services +{ + internal class DataModelService : IDataModelService + { + public DataModelService(IPluginService pluginService) + { + // Add data models of already loaded plugins + foreach (var module in pluginService.GetPluginsOfType()) + AddModuleDataModel(module); + foreach (var dataModelExpansion in pluginService.GetPluginsOfType()) + AddDataModelExpansionDataModel(dataModelExpansion); + + // Add data models of new plugins when they get enabled + pluginService.PluginEnabled += PluginServiceOnPluginEnabled; + } + + public DataModelRegistration RegisterDataModel(DataModel dataModel) + { + if (dataModel == null) + throw new ArgumentNullException(nameof(dataModel)); + return DataModelStore.Add(dataModel); + } + + public void RemoveDataModel(DataModelRegistration registration) + { + if (registration == null) + throw new ArgumentNullException(nameof(registration)); + DataModelStore.Remove(registration); + } + + public List GetDataModels() + { + return DataModelStore.GetAll().Select(d => d.DataModel).ToList(); + } + + public T GetDataModel() where T : DataModel + { + return (T) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel; + } + + public DataModel GetPluginDataModel(Plugin plugin) + { + return DataModelStore.Get(plugin.PluginInfo.Guid)?.DataModel; + } + + public DataModel GetPluginDataModel(Guid pluginGuid) + { + return DataModelStore.Get(pluginGuid)?.DataModel; + } + + private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) + { + if (e.PluginInfo.Instance is Module module) + AddModuleDataModel(module); + else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion) + AddDataModelExpansionDataModel(dataModelExpansion); + } + + private void AddModuleDataModel(Module module) + { + if (module.InternalDataModel == null) + return; + + if (module.InternalDataModel.DataModelDescription == null) + throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null"); + + module.InternalDataModel.IsExpansion = module.InternalExpandsMainDataModel; + RegisterDataModel(module.InternalDataModel); + } + + private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion) + { + if (dataModelExpansion.InternalDataModel.DataModelDescription == null) + throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null"); + + dataModelExpansion.InternalDataModel.IsExpansion = true; + RegisterDataModel(dataModelExpansion.InternalDataModel); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs new file mode 100644 index 000000000..f59eb587d --- /dev/null +++ b/src/Artemis.Core/Services/Registration/Interfaces/IConditionOperatorService.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Artemis.Core.Properties; + +namespace Artemis.Core.Services +{ + /// + /// A service that allows you to register and retrieve conditions operators used by display conditions + /// + public interface IConditionOperatorService : IArtemisService + { + /// + /// Registers a new condition operator for use in layer conditions + /// + /// The PluginInfo of the plugin this condition operator belongs to + /// The condition operator to register + ConditionOperatorRegistration RegisterConditionOperator([NotNull] PluginInfo pluginInfo, [NotNull] ConditionOperator conditionOperator); + + /// + /// Removes a condition operator so it is no longer available for use in layer conditions + /// + /// The registration of the condition operator to remove + void RemoveConditionOperator([NotNull] ConditionOperatorRegistration registration); + + /// + /// Returns all the condition operators compatible with the provided type + /// + List GetConditionOperatorsForType(Type type); + + /// + /// Gets a condition operator by its plugin GUID and type name + /// + /// The operator's plugin GUID + /// The type name of the operator + ConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/IDataBindingService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs similarity index 60% rename from src/Artemis.Core/Services/Interfaces/IDataBindingService.cs rename to src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs index 1ed4bbeb2..b40248b37 100644 --- a/src/Artemis.Core/Services/Interfaces/IDataBindingService.cs +++ b/src/Artemis.Core/Services/Registration/Interfaces/IDataBindingService.cs @@ -1,29 +1,26 @@ using System; using System.Collections.Generic; using Artemis.Core.Properties; -using Newtonsoft.Json; namespace Artemis.Core.Services { + /// + /// A service that allows you to register and retrieve data binding modifiers used by the data bindings system + /// public interface IDataBindingService : IArtemisService { - /// - /// Gets a read-only collection of all registered modifier types - /// - IReadOnlyCollection RegisteredDataBindingModifierTypes { get; } - /// /// Registers a new modifier type for use in data bindings /// /// The PluginInfo of the plugin this modifier type belongs to /// The modifier type to register - void RegisterModifierType([NotNull] PluginInfo pluginInfo, [NotNull] DataBindingModifierType dataBindingModifierType); + DataBindingModifierTypeRegistration RegisterModifierType([NotNull] PluginInfo pluginInfo, [NotNull] DataBindingModifierType dataBindingModifierType); /// /// Removes a modifier type so it is no longer available for use in data bindings /// - /// The modifier type to remove - void RemoveModifierType([NotNull] DataBindingModifierType dataBindingModifierType); + /// The registration of the modifier type to remove + void RemoveModifierType([NotNull] DataBindingModifierTypeRegistration dataBindingModifierType); /// /// Returns all the data binding modifier types compatible with the provided type @@ -37,12 +34,5 @@ namespace Artemis.Core.Services /// The type name of the modifier type /// DataBindingModifierType GetModifierType(Guid modifierTypePluginGuid, string modifierType); - - /// - /// Logs a modifier deserialization failure - /// - /// The modifier that failed to deserialize - /// The JSON exception that occurred - void LogModifierDeserializationFailure(string modifierName, JsonSerializationException exception); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs new file mode 100644 index 000000000..c9ab8a279 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/Interfaces/IDataModelService.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Artemis.Core.DataModelExpansions; + +namespace Artemis.Core.Services +{ + /// + /// A service that allows you to register and retrieve data models + /// + public interface IDataModelService : IArtemisService + { + /// + /// Add a data model to so that it is available to conditions and data bindings + /// + /// + DataModelRegistration RegisterDataModel(DataModel dataModel); + + /// + /// Remove a previously added data model so that it is no longer available + /// + void RemoveDataModel(DataModelRegistration registration); + + /// + /// Returns a list of all registered data models + /// + List GetDataModels(); + + /// + /// If found, returns the registered data model of type + /// + /// The type of the data model to find + T GetDataModel() where T : DataModel; + + /// + /// If found, returns the data model of the provided plugin + /// + /// The plugin to find the data model of + DataModel GetPluginDataModel(Plugin plugin); + + /// + /// If found, returns the data model of the provided plugin GUID + /// + /// The GUID of the plugin to find the data model of + DataModel GetPluginDataModel(Guid pluginGuid); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs b/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs new file mode 100644 index 000000000..8bc6a62e0 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/Interfaces/ILayerBrushService.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Artemis.Core.LayerBrushes; + +namespace Artemis.Core.Services +{ + /// + /// A service that allows you to register and retrieve layer brushes + /// + public interface ILayerBrushService : IArtemisService + { + /// + /// Add a layer brush descriptor so that it is available to layers + /// + LayerBrushRegistration RegisterLayerBrush(LayerBrushDescriptor descriptor); + + /// + /// Remove a previously added layer brush descriptor so that it is no longer available + /// + void RemoveLayerBrush(LayerBrushRegistration registration); + + /// + /// Returns a list of all registered layer brush descriptors + /// + List GetLayerBrushes(); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/Interfaces/ILayerEffectService.cs b/src/Artemis.Core/Services/Registration/Interfaces/ILayerEffectService.cs new file mode 100644 index 000000000..1bb093200 --- /dev/null +++ b/src/Artemis.Core/Services/Registration/Interfaces/ILayerEffectService.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Artemis.Core.LayerBrushes; +using Artemis.Core.LayerEffects; + +namespace Artemis.Core.Services +{ + /// + /// A service that allows you to register and retrieve layer brushes + /// + public interface ILayerEffectService : IArtemisService + { + /// + /// Add an effect descriptor so that it is available to profile elements + /// + LayerEffectRegistration RegisterLayerEffect(LayerEffectDescriptor descriptor); + + /// + /// Remove a previously added layer effect descriptor so that it is no longer available + /// + void RemoveLayerEffect(LayerEffectRegistration registration); + + /// + /// Returns a list of all registered layer effect descriptors + /// + List GetLayerEffects(); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/LayerBrushService.cs b/src/Artemis.Core/Services/Registration/LayerBrushService.cs new file mode 100644 index 000000000..582a988ff --- /dev/null +++ b/src/Artemis.Core/Services/Registration/LayerBrushService.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.LayerBrushes; +using Ninject; + +namespace Artemis.Core.Services +{ + internal class LayerBrushService : ILayerBrushService + { + private readonly IKernel _kernel; + + public LayerBrushService(IKernel kernel) + { + _kernel = kernel; + } + public LayerBrushRegistration RegisterLayerBrush(LayerBrushDescriptor descriptor) + { + if (descriptor == null) + throw new ArgumentNullException(nameof(descriptor)); + + descriptor.Kernel = _kernel; + return LayerBrushStore.Add(descriptor); + } + + public void RemoveLayerBrush(LayerBrushRegistration registration) + { + if (registration == null) + throw new ArgumentNullException(nameof(registration)); + LayerBrushStore.Remove(registration); + } + + public List GetLayerBrushes() + { + return LayerBrushStore.GetAll().Select(r => r.LayerBrushDescriptor).ToList(); + } + } +} diff --git a/src/Artemis.Core/Services/Registration/LayerEffectService.cs b/src/Artemis.Core/Services/Registration/LayerEffectService.cs new file mode 100644 index 000000000..160c712df --- /dev/null +++ b/src/Artemis.Core/Services/Registration/LayerEffectService.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.LayerEffects; +using Ninject; + +namespace Artemis.Core.Services +{ + internal class LayerEffectService : ILayerEffectService + { + private readonly IKernel _kernel; + + public LayerEffectService(IKernel kernel) + { + _kernel = kernel; + } + + public LayerEffectRegistration RegisterLayerEffect(LayerEffectDescriptor descriptor) + { + if (descriptor == null) + throw new ArgumentNullException(nameof(descriptor)); + + descriptor.Kernel = _kernel; + return LayerEffectStore.Add(descriptor); + } + + public void RemoveLayerEffect(LayerEffectRegistration registration) + { + if (registration == null) + throw new ArgumentNullException(nameof(registration)); + LayerEffectStore.Remove(registration); + } + + public List GetLayerEffects() + { + return LayerEffectStore.GetAll().Select(r => r.LayerEffectDescriptor).ToList(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/RenderElementService.cs b/src/Artemis.Core/Services/RenderElementService.cs deleted file mode 100644 index fed3caf7a..000000000 --- a/src/Artemis.Core/Services/RenderElementService.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Linq; -using Artemis.Core.LayerBrushes; -using Artemis.Core.LayerEffects; -using Ninject; -using Serilog; - -namespace Artemis.Core.Services -{ - internal class RenderElementService : IRenderElementService - { - private readonly IDataModelService _dataModelService; - private readonly IDataBindingService _dataBindingService; - private readonly IKernel _kernel; - private readonly ILogger _logger; - private readonly IPluginService _pluginService; - - public RenderElementService(IKernel kernel, ILogger logger, IPluginService pluginService, IDataModelService dataModelService, IDataBindingService dataBindingService) - { - _kernel = kernel; - _logger = logger; - _pluginService = pluginService; - _dataModelService = dataModelService; - _dataBindingService = dataBindingService; - } - - public Layer CreateLayer(Profile profile, ProfileElement parent, string name) - { - var layer = new Layer(profile, parent, name); - parent.AddChild(layer); - - // Layers have two hardcoded property groups, instantiate them - layer.General.Initialize(layer, "General.", Constants.CorePluginInfo); - layer.Transform.Initialize(layer, "Transform.", Constants.CorePluginInfo); - - // With the properties loaded, the layer brush and effect can be instantiated - InstantiateLayerBrush(layer); - InstantiateLayerEffects(layer); - InstantiateDisplayConditions(layer); - InstantiateDataBindings(layer); - return layer; - } - - public void RemoveLayerBrush(Layer layer) - { - layer.RemoveLayerBrush(); - layer.OnLayerBrushUpdated(); - } - - public void DeactivateLayerBrush(Layer layer) - { - layer.DeactivateLayerBrush(); - layer.OnLayerBrushUpdated(); - } - - public BaseLayerBrush InstantiateLayerBrush(Layer layer) - { - if (layer.LayerBrush != null) - throw new ArtemisCoreException("Layer already has an instantiated layer brush"); - - var descriptorReference = layer.General.BrushReference?.CurrentValue; - if (descriptorReference == null) - return null; - - // Get a matching descriptor - var layerBrushProviders = _pluginService.GetPluginsOfType(); - var descriptors = layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors).ToList(); - var descriptor = descriptors.FirstOrDefault(d => d.LayerBrushProvider.PluginInfo.Guid == descriptorReference.BrushPluginGuid && - d.LayerBrushType.Name == descriptorReference.BrushType); - - if (descriptor == null) - return null; - - var brush = (BaseLayerBrush) _kernel.Get(descriptor.LayerBrushType); - brush.Layer = layer; - brush.Descriptor = descriptor; - brush.Initialize(); - brush.Update(0); - - layer.LayerBrush = brush; - layer.OnLayerBrushUpdated(); - - return brush; - } - - public BaseLayerEffect AddLayerEffect(RenderProfileElement renderElement, LayerEffectDescriptor layerEffectDescriptor) - { - // Create the effect with dependency injection - var effect = (BaseLayerEffect) _kernel.Get(layerEffectDescriptor.LayerEffectType); - - effect.ProfileElement = renderElement; - effect.EntityId = Guid.NewGuid(); - effect.Enabled = true; - effect.Order = renderElement.LayerEffects.Count + 1; - effect.Descriptor = layerEffectDescriptor; - - effect.Initialize(); - effect.Update(0); - - renderElement.AddLayerEffect(effect); - _logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath); - return effect; - } - - public void RemoveLayerEffect(BaseLayerEffect layerEffect) - { - layerEffect.ProfileElement.RemoveLayerEffect(layerEffect); - } - - public void InstantiateLayerEffects(RenderProfileElement renderElement) - { - var layerEffectProviders = _pluginService.GetPluginsOfType(); - var descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); - var entities = renderElement.RenderElementEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); - - foreach (var layerEffectEntity in entities) - { - // Skip effects already on the element - if (renderElement.LayerEffects.Any(e => e.EntityId == layerEffectEntity.Id)) - continue; - - // Get a matching descriptor - var descriptor = descriptors.FirstOrDefault(d => d.LayerEffectProvider.PluginInfo.Guid == layerEffectEntity.PluginGuid && - d.LayerEffectType.Name == layerEffectEntity.EffectType); - if (descriptor == null) - continue; - - // Create the effect with dependency injection - var effect = (BaseLayerEffect) _kernel.Get(descriptor.LayerEffectType); - - effect.ProfileElement = renderElement; - effect.EntityId = layerEffectEntity.Id; - effect.Order = layerEffectEntity.Order; - effect.Name = layerEffectEntity.Name; - effect.Enabled = layerEffectEntity.Enabled; - effect.Descriptor = descriptor; - - effect.Initialize(); - effect.Update(0); - - renderElement.AddLayerEffect(effect); - _logger.Debug("Instantiated layer effect with root path {rootPath}", effect.PropertyRootPath); - } - } - - public void InstantiateDisplayConditions(RenderProfileElement renderElement) - { - var displayCondition = renderElement.RenderElementEntity.RootDisplayCondition != null - ? new DisplayConditionGroup(null, renderElement.RenderElementEntity.RootDisplayCondition) - : new DisplayConditionGroup(null); - - try - { - displayCondition.Initialize(_dataModelService); - renderElement.DisplayConditionGroup = displayCondition; - } - catch (Exception e) - { - _logger.Warning(e, $"Failed to init display conditions for {renderElement}"); - } - } - - public void InstantiateDataBindings(RenderProfileElement renderElement) - { - renderElement.InitializeDataBindings(_dataBindingService, _dataModelService); - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index df10d1a78..c80e36736 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -10,7 +10,7 @@ namespace Artemis.Core.Services /// /// Provides wrapped access the RGB.NET /// - internal class RgbService : IRgbService, IDisposable + internal class RgbService : IRgbService { private readonly List _loadedDevices; private readonly ILogger _logger; diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 6b50447c4..49c575d8e 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -158,13 +158,13 @@ namespace Artemis.Core.Services profile.RedoStack.Clear(); profile.UndoStack.Push(memento); - profile.ApplyToEntity(); + profile.Save(); if (includeChildren) { foreach (var folder in profile.GetAllFolders()) - folder.ApplyToEntity(); + folder.Save(); foreach (var layer in profile.GetAllLayers()) - layer.ApplyToEntity(); + layer.Save(); } _profileRepository.Save(profile.ProfileEntity); diff --git a/src/Artemis.Core/Stores/ConditionOperatorStore.cs b/src/Artemis.Core/Stores/ConditionOperatorStore.cs new file mode 100644 index 000000000..194188084 --- /dev/null +++ b/src/Artemis.Core/Stores/ConditionOperatorStore.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Core +{ + internal class ConditionOperatorStore + { + private static readonly List Registrations = new List(); + + public static ConditionOperatorRegistration Add(ConditionOperator conditionOperator) + { + ConditionOperatorRegistration registration; + lock (Registrations) + { + if (Registrations.Any(r => r.ConditionOperator == conditionOperator)) + throw new ArtemisCoreException($"Condition operator store store already contains operator '{conditionOperator.Description}'"); + + registration = new ConditionOperatorRegistration(conditionOperator, conditionOperator.PluginInfo.Instance) {IsInStore = true}; + Registrations.Add(registration); + } + + OnConditionOperatorAdded(new ConditionOperatorStoreEvent(registration)); + return registration; + } + + public static void Remove(ConditionOperatorRegistration registration) + { + lock (Registrations) + { + if (!Registrations.Contains(registration)) + throw new ArtemisCoreException($"Condition operator store does not contain operator '{registration.ConditionOperator.Description}'"); + + Registrations.Remove(registration); + registration.IsInStore = false; + } + + OnConditionOperatorRemoved(new ConditionOperatorStoreEvent(registration)); + } + + public static ConditionOperatorRegistration Get(Guid pluginGuid, string type) + { + lock (Registrations) + { + return Registrations.FirstOrDefault(r => r.Plugin.PluginInfo.Guid == pluginGuid && r.ConditionOperator.GetType().Name == type); + } + } + + public static List GetForType(Type type) + { + lock (Registrations) + { + if (type == null) + return new List(Registrations); + + var candidates = Registrations.Where(r => r.ConditionOperator.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList(); + + // If there are multiple operators with the same description, use the closest match + foreach (var displayConditionOperators in candidates.GroupBy(r => r.ConditionOperator.Description).Where(g => g.Count() > 1).ToList()) + { + var closest = displayConditionOperators.OrderByDescending(r => r.ConditionOperator.CompatibleTypes.Contains(type)).FirstOrDefault(); + foreach (var displayConditionOperator in displayConditionOperators) + { + if (displayConditionOperator != closest) + candidates.Remove(displayConditionOperator); + } + } + + return candidates; + } + } + + #region Events + + public static event EventHandler ConditionOperatorAdded; + public static event EventHandler ConditionOperatorRemoved; + + private static void OnConditionOperatorAdded(ConditionOperatorStoreEvent e) + { + ConditionOperatorAdded?.Invoke(null, e); + } + + private static void OnConditionOperatorRemoved(ConditionOperatorStoreEvent e) + { + ConditionOperatorRemoved?.Invoke(null, e); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs new file mode 100644 index 000000000..b398ed925 --- /dev/null +++ b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Core +{ + internal class DataBindingModifierTypeStore + { + private static readonly List Registrations = new List(); + + public static DataBindingModifierTypeRegistration Add(DataBindingModifierType modifierType) + { + DataBindingModifierTypeRegistration typeRegistration; + lock (Registrations) + { + if (Registrations.Any(r => r.DataBindingModifierType == modifierType)) + throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{modifierType.Description}'"); + + typeRegistration = new DataBindingModifierTypeRegistration(modifierType, modifierType.PluginInfo.Instance) { IsInStore = true }; + Registrations.Add(typeRegistration); + } + + OnDataBindingModifierAdded(new DataBindingModifierTypeStoreEvent(typeRegistration)); + return typeRegistration; + } + + public static void Remove(DataBindingModifierTypeRegistration typeRegistration) + { + lock (Registrations) + { + if (!Registrations.Contains(typeRegistration)) + throw new ArtemisCoreException($"Data binding modifier type store does not contain modifier type '{typeRegistration.DataBindingModifierType.Description}'"); + + Registrations.Remove(typeRegistration); + typeRegistration.IsInStore = false; + } + + OnDataBindingModifierRemoved(new DataBindingModifierTypeStoreEvent(typeRegistration)); + } + + public static DataBindingModifierTypeRegistration Get(Guid pluginGuid, string type) + { + lock (Registrations) + { + return Registrations.FirstOrDefault(r => r.Plugin.PluginInfo.Guid == pluginGuid && r.DataBindingModifierType.GetType().Name == type); + } + } + + public static List GetForType(Type type) + { + lock (Registrations) + { + if (type == null) + return new List(Registrations); + + var candidates = Registrations.Where(r => r.DataBindingModifierType.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList(); + + // If there are multiple operators with the same description, use the closest match + foreach (var displayDataBindingModifiers in candidates.GroupBy(r => r.DataBindingModifierType.Description).Where(g => g.Count() > 1).ToList()) + { + var closest = displayDataBindingModifiers.OrderByDescending(r => r.DataBindingModifierType.CompatibleTypes.Contains(type)).FirstOrDefault(); + foreach (var displayDataBindingModifier in displayDataBindingModifiers) + { + if (displayDataBindingModifier != closest) + candidates.Remove(displayDataBindingModifier); + } + } + + return candidates; + } + } + + #region Events + + public static event EventHandler DataBindingModifierAdded; + public static event EventHandler DataBindingModifierRemoved; + + private static void OnDataBindingModifierAdded(DataBindingModifierTypeStoreEvent e) + { + DataBindingModifierAdded?.Invoke(null, e); + } + + private static void OnDataBindingModifierRemoved(DataBindingModifierTypeStoreEvent e) + { + DataBindingModifierRemoved?.Invoke(null, e); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/DataModelStore.cs b/src/Artemis.Core/Stores/DataModelStore.cs new file mode 100644 index 000000000..2617e91f7 --- /dev/null +++ b/src/Artemis.Core/Stores/DataModelStore.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.DataModelExpansions; + +namespace Artemis.Core +{ + internal class DataModelStore + { + private static readonly List Registrations = new List(); + + public static DataModelRegistration Add(DataModel dataModel) + { + DataModelRegistration registration; + lock (Registrations) + { + if (Registrations.Any(r => r.DataModel == dataModel)) + throw new ArtemisCoreException($"Data model store already contains data model '{dataModel.DataModelDescription}'"); + + registration = new DataModelRegistration(dataModel, dataModel.PluginInfo.Instance) {IsInStore = true}; + Registrations.Add(registration); + } + + OnDataModelAdded(new DataModelStoreEvent(registration)); + return registration; + } + + public static void Remove(DataModelRegistration registration) + { + lock (Registrations) + { + if (!Registrations.Contains(registration)) + throw new ArtemisCoreException($"Data model store does not contain data model '{registration.DataModel.DataModelDescription}'"); + + Registrations.Remove(registration); + registration.IsInStore = false; + } + + OnDataModelRemoved(new DataModelStoreEvent(registration)); + } + + public static List GetAll() + { + lock (Registrations) + { + return new List(Registrations); + } + } + + public static DataModelRegistration Get(Guid pluginGuid) + { + lock (Registrations) + { + return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid); + } + } + + #region Events + + public static event EventHandler DataModelAdded; + public static event EventHandler DataModelRemoved; + + private static void OnDataModelAdded(DataModelStoreEvent e) + { + DataModelAdded?.Invoke(null, e); + } + + private static void OnDataModelRemoved(DataModelStoreEvent e) + { + DataModelRemoved?.Invoke(null, e); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/LayerBrushStore.cs b/src/Artemis.Core/Stores/LayerBrushStore.cs new file mode 100644 index 000000000..75af208b0 --- /dev/null +++ b/src/Artemis.Core/Stores/LayerBrushStore.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.LayerBrushes; + +namespace Artemis.Core +{ + internal class LayerBrushStore + { + private static readonly List Registrations = new List(); + + public static LayerBrushRegistration Add(LayerBrushDescriptor descriptor) + { + LayerBrushRegistration registration; + lock (Registrations) + { + if (Registrations.Any(r => r.LayerBrushDescriptor == descriptor)) + throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); + + registration = new LayerBrushRegistration(descriptor, descriptor.LayerBrushProvider.PluginInfo.Instance) {IsInStore = true}; + Registrations.Add(registration); + } + + OnLayerBrushAdded(new LayerBrushStoreEvent(registration)); + return registration; + } + + public static void Remove(LayerBrushRegistration registration) + { + lock (Registrations) + { + if (!Registrations.Contains(registration)) + throw new ArtemisCoreException($"Store does not contain layer brush '{registration.LayerBrushDescriptor.DisplayName}'"); + + Registrations.Remove(registration); + registration.IsInStore = false; + } + + OnLayerBrushRemoved(new LayerBrushStoreEvent(registration)); + } + + public static List GetAll() + { + lock (Registrations) + { + return new List(Registrations); + } + } + + public static LayerBrushRegistration Get(Guid pluginGuid, string typeName) + { + lock (Registrations) + { + return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid && d.LayerBrushDescriptor.LayerBrushType.Name == typeName); + } + } + + #region Events + + public static event EventHandler LayerBrushAdded; + public static event EventHandler LayerBrushRemoved; + + private static void OnLayerBrushAdded(LayerBrushStoreEvent e) + { + LayerBrushAdded?.Invoke(null, e); + } + + private static void OnLayerBrushRemoved(LayerBrushStoreEvent e) + { + LayerBrushRemoved?.Invoke(null, e); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/LayerEffectStore.cs b/src/Artemis.Core/Stores/LayerEffectStore.cs new file mode 100644 index 000000000..7e78e22bc --- /dev/null +++ b/src/Artemis.Core/Stores/LayerEffectStore.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.LayerEffects; + +namespace Artemis.Core +{ + internal class LayerEffectStore + { + private static readonly List Registrations = new List(); + + public static LayerEffectRegistration Add(LayerEffectDescriptor descriptor) + { + LayerEffectRegistration registration; + lock (Registrations) + { + if (Registrations.Any(r => r.LayerEffectDescriptor == descriptor)) + throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); + + registration = new LayerEffectRegistration(descriptor, descriptor.LayerEffectProvider.PluginInfo.Instance) { IsInStore = true }; + Registrations.Add(registration); + } + + OnLayerEffectAdded(new LayerEffectStoreEvent(registration)); + return registration; + } + + public static void Remove(LayerEffectRegistration registration) + { + lock (Registrations) + { + if (!Registrations.Contains(registration)) + throw new ArtemisCoreException($"Store does not contain layer brush '{registration.LayerEffectDescriptor.DisplayName}'"); + + Registrations.Remove(registration); + registration.IsInStore = false; + } + + OnLayerEffectRemoved(new LayerEffectStoreEvent(registration)); + } + + public static List GetAll() + { + lock (Registrations) + { + return new List(Registrations); + } + } + + public static LayerEffectRegistration Get(Guid pluginGuid, string typeName) + { + lock (Registrations) + { + return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid && d.LayerEffectDescriptor.LayerEffectType.Name == typeName); + } + } + + #region Events + + public static event EventHandler LayerEffectAdded; + public static event EventHandler LayerEffectRemoved; + + private static void OnLayerEffectAdded(LayerEffectStoreEvent e) + { + LayerEffectAdded?.Invoke(null, e); + } + + private static void OnLayerEffectRemoved(LayerEffectStoreEvent e) + { + LayerEffectRemoved?.Invoke(null, e); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs new file mode 100644 index 000000000..babd6da7e --- /dev/null +++ b/src/Artemis.Core/Stores/Registrations/ConditionOperatorRegistration.cs @@ -0,0 +1,40 @@ +using System; + +namespace Artemis.Core +{ + /// + /// Represents a data model registration + /// + public class ConditionOperatorRegistration + { + internal ConditionOperatorRegistration(ConditionOperator conditionOperator, Plugin plugin) + { + ConditionOperator = conditionOperator; + Plugin = plugin; + + Plugin.PluginDisabled += PluginOnPluginDisabled; + } + + /// + /// Gets the condition operator that has been registered + /// + public ConditionOperator ConditionOperator { get; } + + /// + /// Gets the plugin the condition operator is associated with + /// + public Plugin Plugin { get; } + + /// + /// Gets a boolean indicating whether the registration is in the internal Core store + /// + public bool IsInStore { get; internal set; } + + private void PluginOnPluginDisabled(object sender, EventArgs e) + { + Plugin.PluginDisabled -= PluginOnPluginDisabled; + if (IsInStore) + ConditionOperatorStore.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs new file mode 100644 index 000000000..d00e19444 --- /dev/null +++ b/src/Artemis.Core/Stores/Registrations/DataBindingModifierTypeRegistration.cs @@ -0,0 +1,40 @@ +using System; + +namespace Artemis.Core +{ + /// + /// Represents a data model registration + /// + public class DataBindingModifierTypeRegistration + { + internal DataBindingModifierTypeRegistration(DataBindingModifierType dataBindingModifierType, Plugin plugin) + { + DataBindingModifierType = dataBindingModifierType; + Plugin = plugin; + + Plugin.PluginDisabled += PluginOnPluginDisabled; + } + + /// + /// Gets the data binding modifier that has been registered + /// + public DataBindingModifierType DataBindingModifierType { get; } + + /// + /// Gets the plugin the data binding modifier is associated with + /// + public Plugin Plugin { get; } + + /// + /// Gets a boolean indicating whether the registration is in the internal Core store + /// + public bool IsInStore { get; internal set; } + + private void PluginOnPluginDisabled(object sender, EventArgs e) + { + Plugin.PluginDisabled -= PluginOnPluginDisabled; + if (IsInStore) + DataBindingModifierTypeStore.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs new file mode 100644 index 000000000..336a64c96 --- /dev/null +++ b/src/Artemis.Core/Stores/Registrations/DataModelRegistration.cs @@ -0,0 +1,41 @@ +using System; +using Artemis.Core.DataModelExpansions; + +namespace Artemis.Core +{ + /// + /// Represents a data model registration + /// + public class DataModelRegistration + { + internal DataModelRegistration(DataModel dataModel, Plugin plugin) + { + DataModel = dataModel; + Plugin = plugin; + + Plugin.PluginDisabled += PluginOnPluginDisabled; + } + + /// + /// Gets the data model that has been registered + /// + public DataModel DataModel { get; } + + /// + /// Gets the plugin the data model is associated with + /// + public Plugin Plugin { get; } + + /// + /// Gets a boolean indicating whether the registration is in the internal Core store + /// + public bool IsInStore { get; internal set; } + + private void PluginOnPluginDisabled(object sender, EventArgs e) + { + Plugin.PluginDisabled -= PluginOnPluginDisabled; + if (IsInStore) + DataModelStore.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs new file mode 100644 index 000000000..eeda91812 --- /dev/null +++ b/src/Artemis.Core/Stores/Registrations/LayerBrushRegistration.cs @@ -0,0 +1,41 @@ +using System; +using Artemis.Core.LayerBrushes; + +namespace Artemis.Core +{ + /// + /// Represents a layer brush registration + /// + public class LayerBrushRegistration + { + internal LayerBrushRegistration(LayerBrushDescriptor descriptor, Plugin plugin) + { + LayerBrushDescriptor = descriptor; + Plugin = plugin; + + Plugin.PluginDisabled += PluginOnPluginDisabled; + } + + /// + /// Gets the layer brush descriptor that has been registered + /// + public LayerBrushDescriptor LayerBrushDescriptor { get; } + + /// + /// Gets the plugin the layer brush is associated with + /// + public Plugin Plugin { get; } + + /// + /// Gets a boolean indicating whether the registration is in the internal Core store + /// + public bool IsInStore { get; internal set; } + + private void PluginOnPluginDisabled(object sender, EventArgs e) + { + Plugin.PluginDisabled -= PluginOnPluginDisabled; + if (IsInStore) + LayerBrushStore.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs new file mode 100644 index 000000000..992acf616 --- /dev/null +++ b/src/Artemis.Core/Stores/Registrations/LayerEffectRegistration.cs @@ -0,0 +1,41 @@ +using System; +using Artemis.Core.LayerEffects; + +namespace Artemis.Core +{ + /// + /// Represents a layer effect registration + /// + public class LayerEffectRegistration + { + internal LayerEffectRegistration(LayerEffectDescriptor descriptor, Plugin plugin) + { + LayerEffectDescriptor = descriptor; + Plugin = plugin; + + Plugin.PluginDisabled += PluginOnPluginDisabled; + } + + /// + /// Gets the layer effect descriptor that has been registered + /// + public LayerEffectDescriptor LayerEffectDescriptor { get; } + + /// + /// Gets the plugin the layer effect is associated with + /// + public Plugin Plugin { get; } + + /// + /// Gets a boolean indicating whether the registration is in the internal Core store + /// + public bool IsInStore { get; internal set; } + + private void PluginOnPluginDisabled(object sender, EventArgs e) + { + Plugin.PluginDisabled -= PluginOnPluginDisabled; + if (IsInStore) + LayerEffectStore.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Utilities/DeserializationLogger.cs b/src/Artemis.Core/Utilities/DeserializationLogger.cs new file mode 100644 index 000000000..1be7ad7fb --- /dev/null +++ b/src/Artemis.Core/Utilities/DeserializationLogger.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; +using Ninject; +using Serilog; + +namespace Artemis.Core +{ + internal static class DeserializationLogger + { + private static ILogger _logger; + + public static void Initialize(IKernel kernel) + { + _logger = kernel.Get(); + } + + public static void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception) + { + _logger.Warning( + exception, + "Failed to deserialize display condition predicate {left} {operator} {right}", + displayConditionPredicate.Entity.LeftPropertyPath, + displayConditionPredicate.Entity.OperatorType, + displayConditionPredicate.Entity.RightPropertyPath + ); + } + + public static void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionPredicate, JsonException exception) + { + _logger.Warning( + exception, + "Failed to deserialize display condition list predicate {list} => {left} {operator} {right}", + displayConditionPredicate.Entity.ListPropertyPath, + displayConditionPredicate.Entity.LeftPropertyPath, + displayConditionPredicate.Entity.OperatorType, + displayConditionPredicate.Entity.RightPropertyPath + ); + } + + public static void LogModifierDeserializationFailure(string modifierName, JsonSerializationException exception) + { + _logger.Warning(exception, "Failed to deserialize static parameter for modifier {modifierName}", modifierName); + } + } +} diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs index e02fadd81..08e7165ec 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs @@ -26,13 +26,13 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions private readonly Timer _updateTimer; private bool _isInitialized; private DataModelVisualizationViewModel _leftSideDataModel; - private BindableCollection _operators; + private BindableCollection _operators; private DataModelVisualizationViewModel _rightSideDataModel; private DataModelInputViewModel _rightSideInputViewModel; private int _rightSideTransitionIndex; private object _rightStaticValue; private DataModelVisualizationViewModel _selectedLeftSideProperty; - private DisplayConditionOperator _selectedOperator; + private ConditionOperator _selectedOperator; private DataModelVisualizationViewModel _selectedRightSideProperty; private List _supportedInputTypes; @@ -56,7 +56,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions SelectLeftPropertyCommand = new DelegateCommand(ExecuteSelectLeftProperty); SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty); SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand); - Operators = new BindableCollection(); + Operators = new BindableCollection(); ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues"); @@ -125,13 +125,13 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions set => SetAndNotify(ref _rightSideInputViewModel, value); } - public BindableCollection Operators + public BindableCollection Operators { get => _operators; set => SetAndNotify(ref _operators, value); } - public DisplayConditionOperator SelectedOperator + public ConditionOperator SelectedOperator { get => _selectedOperator; set => SetAndNotify(ref _selectedOperator, value); @@ -206,7 +206,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions // Get the supported operators Operators.Clear(); - Operators.AddRange(_dataModelService.GetCompatibleConditionOperators(leftSideType)); + Operators.AddRange(_dataModelService.GetConditionOperatorsForType(leftSideType)); if (DisplayConditionListPredicate.Operator == null) DisplayConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); SelectedOperator = DisplayConditionListPredicate.Operator; @@ -347,7 +347,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions private void ExecuteSelectOperatorCommand(object context) { - if (!(context is DisplayConditionOperator displayConditionOperator)) + if (!(context is ConditionOperator displayConditionOperator)) return; SelectedOperator = displayConditionOperator; diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs index 2b38b9c51..a7750ee91 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs @@ -25,13 +25,13 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions private readonly Timer _updateTimer; private bool _isInitialized; private DataModelPropertiesViewModel _leftSideDataModel; - private BindableCollection _operators; + private BindableCollection _operators; private DataModelPropertiesViewModel _rightSideDataModel; private DataModelInputViewModel _rightSideInputViewModel; private int _rightSideTransitionIndex; private object _rightStaticValue; private DataModelVisualizationViewModel _selectedLeftSideProperty; - private DisplayConditionOperator _selectedOperator; + private ConditionOperator _selectedOperator; private DataModelVisualizationViewModel _selectedRightSideProperty; private List _supportedInputTypes; @@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions SelectLeftPropertyCommand = new DelegateCommand(ExecuteSelectLeftProperty); SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty); SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand); - Operators = new BindableCollection(); + Operators = new BindableCollection(); ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues"); @@ -124,13 +124,13 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions set => SetAndNotify(ref _rightSideInputViewModel, value); } - public BindableCollection Operators + public BindableCollection Operators { get => _operators; set => SetAndNotify(ref _operators, value); } - public DisplayConditionOperator SelectedOperator + public ConditionOperator SelectedOperator { get => _selectedOperator; set => SetAndNotify(ref _selectedOperator, value); @@ -208,7 +208,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions // Get the supported operators Operators.Clear(); - Operators.AddRange(_dataModelService.GetCompatibleConditionOperators(leftSideType)); + Operators.AddRange(_dataModelService.GetConditionOperatorsForType(leftSideType)); if (DisplayConditionPredicate.Operator == null) DisplayConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); SelectedOperator = DisplayConditionPredicate.Operator; @@ -329,7 +329,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions private void ExecuteSelectOperatorCommand(object context) { - if (!(context is DisplayConditionOperator displayConditionOperator)) + if (!(context is ConditionOperator displayConditionOperator)) return; SelectedOperator = displayConditionOperator;