From 9417332a073d564f1ee8f0866a92c255037279df Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 7 Oct 2020 23:15:10 +0200 Subject: [PATCH] Conditions - Move to new paths API (more WIP) --- .../DataModelConditionListPredicate.cs | 75 +++++++++++-------- .../ListPredicateWrapperDataModel.cs | 9 +++ .../Models/Profile/DataModel/DataModelPath.cs | 25 +++---- .../Utilities/DeserializationLogger.cs | 4 +- ...ataModelConditionListPredicateViewModel.cs | 16 ++-- .../DataModelConditionListViewModel.cs | 2 +- .../DataModelConditionPredicateViewModel.cs | 9 ++- 7 files changed, 81 insertions(+), 59 deletions(-) create mode 100644 src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs index 22a9491ca..ff023d34b 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs @@ -25,6 +25,7 @@ namespace Artemis.Core PredicateType = predicateType; Entity = new DataModelConditionListPredicateEntity(); + DataModelConditionList = null!; ApplyParentList(); Initialize(); } @@ -35,6 +36,7 @@ namespace Artemis.Core Entity = entity; PredicateType = (ListRightSideType) entity.PredicateType; + DataModelConditionList = null!; ApplyParentList(); Initialize(); } @@ -49,37 +51,22 @@ namespace Artemis.Core /// /// Gets the operator /// - public ConditionOperator Operator { get; private set; } + public ConditionOperator? Operator { get; private set; } /// /// Gets the data model condition list this predicate belongs to /// public DataModelConditionList DataModelConditionList { get; private set; } - /// - /// Gets the path of the left property in the - /// - public string LeftPropertyPath { get; private set; } + public DataModelPath? LeftPath { get; set; } - /// - /// Gets the currently used instance of the right side data model - /// Note: This is null when using a path inside the list - /// - public DataModel RightDataModel { get; set; } - - /// - /// Gets the path of the right property in the - /// - public string RightPropertyPath { get; private set; } + public DataModelPath? RightPath { get; set; } /// /// Gets the right static value, only used it is /// /// - public object RightStaticValue { get; private set; } - - public Func LeftSideAccessor { get; set; } - public Func RightSideAccessor { get; set; } + public object? RightStaticValue { get; private set; } /// /// Updates the left side of the predicate @@ -92,7 +79,8 @@ namespace Artemis.Core if (!ListContainsInnerPath(path)) throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}"); - LeftPropertyPath = path; + LeftPath?.Dispose(); + LeftPath = new DataModelPath(new ListPredicateWrapperDataModel(), path); ValidateOperator(); ValidateRightSide(); @@ -110,7 +98,8 @@ namespace Artemis.Core throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}"); PredicateType = ListRightSideType.DynamicList; - RightPropertyPath = path; + RightPath?.Dispose(); + RightPath = new DataModelPath(new ListPredicateWrapperDataModel(), path); CreateExpression(); } @@ -135,8 +124,8 @@ namespace Artemis.Core } PredicateType = ListRightSideType.Dynamic; - RightDataModel = dataModel; - RightPropertyPath = path; + RightPath?.Dispose(); + RightPath = new DataModelPath(dataModel, path); CreateExpression(); } @@ -148,7 +137,8 @@ namespace Artemis.Core public void UpdateRightSideStatic(object staticValue) { PredicateType = ListRightSideType.Static; - RightPropertyPath = null; + RightPath?.Dispose(); + RightPath = null; SetStaticValue(staticValue); CreateExpression(); @@ -166,13 +156,18 @@ namespace Artemis.Core return; } - if (LeftPropertyPath == null) + // No need to clear compiled expressions, without a left data model they are already null + if (LeftPath == null || !LeftPath.IsValid) { Operator = conditionOperator; return; } - Type leftType = GetTypeAtInnerPath(LeftPropertyPath); + Type leftType = LeftPath.GetPropertyType()!; + if (!conditionOperator.SupportsType(leftType)) + throw new ArtemisCoreException($"Cannot apply operator {conditionOperator.GetType().Name} to this predicate because " + + $"it does not support left side type {leftType.Name}"); + if (conditionOperator.SupportsType(leftType)) Operator = conditionOperator; @@ -209,26 +204,30 @@ namespace Artemis.Core return true; } - + internal override bool EvaluateObject(object target) { - if (Operator == null || LeftSideAccessor == null || PredicateType != ListRightSideType.Static && RightSideAccessor == null) + if (Operator == null || LeftPath == null || !LeftPath.IsValid) return false; // Compare with a static value if (PredicateType == ListRightSideType.Static) { - if (!DataModelConditionList.ListType.IsValueType && RightStaticValue == null) + object? leftSideValue = GetListPathValue(LeftPath, target); + if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null) return false; - return Operator.Evaluate(LeftSideAccessor(target), RightStaticValue); + return Operator.Evaluate(leftSideValue, RightStaticValue); } + if (RightPath == null || !RightPath.IsValid) + return false; + // Compare with dynamic values if (PredicateType == ListRightSideType.Dynamic) - return Operator.Evaluate(LeftSideAccessor(target), RightSideAccessor(RightDataModel)); + return Operator.Evaluate(GetListPathValue(LeftPath, target), RightPath.GetValue()); if (PredicateType == ListRightSideType.DynamicList) - return Operator.Evaluate(LeftSideAccessor(target), RightSideAccessor(target)); + return Operator.Evaluate(GetListPathValue(LeftPath, target), GetListPathValue(RightPath, target)); return false; } @@ -444,6 +443,15 @@ namespace Artemis.Core RightStaticValue = null; } + private object? GetListPathValue(DataModelPath path, object target) + { + if (!(path.Target is ListPredicateWrapperDataModel wrapper)) + throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target"); + + wrapper.Value = target; + return path.GetValue(); + } + private void CreateDynamicListAccessors() { if (LeftPropertyPath == null || RightPropertyPath == null || Operator == null) @@ -515,6 +523,9 @@ namespace Artemis.Core ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded; ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved; + LeftPath?.Dispose(); + RightPath?.Dispose(); + base.Dispose(disposing); } diff --git a/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs new file mode 100644 index 000000000..404f6d5b0 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs @@ -0,0 +1,9 @@ +using Artemis.Core.DataModelExpansions; + +namespace Artemis.Core +{ + internal class ListPredicateWrapperDataModel : DataModel + { + public object Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index 906fcc8cb..d28d6b0b7 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -21,13 +21,11 @@ namespace Artemis.Core /// Creates a new instance of the class pointing directly to the target /// /// The target at which this path starts - public DataModelPath(object target) + public DataModelPath(DataModel target) { Target = target ?? throw new ArgumentNullException(nameof(target)); Path = ""; Entity = new DataModelPathEntity(); - if (Target is DataModel dataModel) - DataModelGuid = dataModel.PluginInfo.Guid; _segments = new LinkedList(); @@ -41,13 +39,11 @@ namespace Artemis.Core /// /// The target at which this path starts /// A point-separated path - public DataModelPath(object target, string path) + public DataModelPath(DataModel target, string path) { Target = target ?? throw new ArgumentNullException(nameof(target)); Path = path ?? throw new ArgumentNullException(nameof(path)); Entity = new DataModelPathEntity(); - if (Target is DataModel dataModel) - DataModelGuid = dataModel.PluginInfo.Guid; _segments = new LinkedList(); @@ -56,9 +52,9 @@ namespace Artemis.Core SubscribeToDataModelStore(); } - internal DataModelPath(object? target, DataModelPathEntity entity) + internal DataModelPath(DataModel? target, DataModelPathEntity entity) { - Target = target!; + Target = target; Path = entity.Path; Entity = entity; @@ -72,14 +68,14 @@ namespace Artemis.Core /// /// Gets the data model at which this path starts /// - public object? Target { get; private set; } + public DataModel? Target { get; private set; } internal DataModelPathEntity Entity { get; } /// /// Gets the data model GUID of the if it is a /// - public Guid? DataModelGuid { get; private set; } + public Guid? DataModelGuid => Target?.PluginInfo.Guid; /// /// Gets the point-separated path associated with this @@ -221,10 +217,9 @@ namespace Artemis.Core public void Load() { Path = Entity.Path; - DataModelGuid = Entity.DataModelGuid; - if (Target == null && Entity.DataModelGuid != null) - Target = DataModelStore.Get(Entity.DataModelGuid.Value); + if (Target == null && Entity.DataModelGuid != null) + Target = DataModelStore.Get(Entity.DataModelGuid.Value)?.DataModel; } /// @@ -253,7 +248,7 @@ namespace Artemis.Core private void DataModelStoreOnDataModelAdded(object? sender, DataModelStoreEvent e) { - if (e.Registration.DataModel.PluginInfo.Guid != DataModelGuid) + if (e.Registration.DataModel.PluginInfo.Guid != Entity.DataModelGuid) return; Target = e.Registration.DataModel; @@ -262,7 +257,7 @@ namespace Artemis.Core private void DataModelStoreOnDataModelRemoved(object? sender, DataModelStoreEvent e) { - if (e.Registration.DataModel.PluginInfo.Guid != DataModelGuid) + if (e.Registration.DataModel.PluginInfo.Guid != Entity.DataModelGuid) return; Target = null; diff --git a/src/Artemis.Core/Utilities/DeserializationLogger.cs b/src/Artemis.Core/Utilities/DeserializationLogger.cs index e0c762c2d..26caddb4e 100644 --- a/src/Artemis.Core/Utilities/DeserializationLogger.cs +++ b/src/Artemis.Core/Utilities/DeserializationLogger.cs @@ -18,9 +18,9 @@ namespace Artemis.Core _logger.Warning( exception, "Failed to deserialize display condition predicate {left} {operator} {right}", - dataModelConditionPredicate.Entity.LeftPropertyPath, + dataModelConditionPredicate.Entity.LeftPath?.Path, dataModelConditionPredicate.Entity.OperatorType, - dataModelConditionPredicate.Entity.RightPropertyPath + dataModelConditionPredicate.Entity.RightPath?.Path ); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs index 84e3c6c61..10e820f58 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs @@ -123,13 +123,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public override void Update() { - Guid listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListDataModel.PluginInfo.Guid; + Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid; + if (listDataModelGuid == null) + return; + if (!_isPrimitiveList) { LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188)); LeftSideSelectionViewModel.SelectedPropertyViewModel = LeftSideSelectionViewModel.DataModelViewModel.GetChildByPath( - listDataModelGuid, DataModelConditionListPredicate.LeftPropertyPath + listDataModelGuid.Value, DataModelConditionListPredicate.LeftPropertyPath ); } @@ -170,7 +173,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions else { RightSideSelectionViewModel.SelectedPropertyViewModel = RightSideSelectionViewModel.DataModelViewModel.GetChildByPath( - listDataModelGuid, DataModelConditionListPredicate.RightPropertyPath + listDataModelGuid.Value, DataModelConditionListPredicate.RightPropertyPath ); } } @@ -236,9 +239,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions private DataModelVisualizationViewModel GetListDataModel() { DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true); + if (DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid == null) + return null; + DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath( - DataModelConditionListPredicate.DataModelConditionList.ListDataModel.PluginInfo.Guid, - DataModelConditionListPredicate.DataModelConditionList.ListPropertyPath + DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value, + DataModelConditionListPredicate.DataModelConditionList.ListPath.Path ); return listDataModel.GetListTypeViewModel(_dataModelUIService); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs index 0e1291382..d0288eb10 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs @@ -107,7 +107,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public override void Update() { - TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListDataModel, DataModelConditionList.ListPropertyPath); + TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath.Target, DataModelConditionList.ListPath.Path); NotifyOfPropertyChange(nameof(SelectedListOperator)); // Remove VMs of effects no longer applied on the layer diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs index 9dfc8e826..64808dd19 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Windows; using System.Windows.Media; using Artemis.Core; +using Artemis.Core.DataModelExpansions; using Artemis.Core.Services; using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract; using Artemis.UI.Shared; @@ -117,8 +118,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions { LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel( - DataModelConditionPredicate.LeftDataModel, - DataModelConditionPredicate.LeftPropertyPath + DataModelConditionPredicate.LeftPath.Target as DataModel, + DataModelConditionPredicate.LeftPath.Path ); Type leftSideType = LeftSideSelectionViewModel.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType(); @@ -147,8 +148,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions } RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( - DataModelConditionPredicate.RightDataModel, - DataModelConditionPredicate.RightPropertyPath + DataModelConditionPredicate.RightPath.Target as DataModel, + DataModelConditionPredicate.RightPath.Path ); RightSideSelectionViewModel.FilterTypes = new[] {targetType}; }