From 805cdc6782c5c80937a1575c7d14124b9c1bed98 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 8 Oct 2020 20:49:23 +0200 Subject: [PATCH] Conditions - Finished migration to new API Conditions UI - Updated for new API, needs simplifying before I'm happy with it --- .../Conditions/DataModelConditionList.cs | 9 ++-- .../DataModelConditionListPredicate.cs | 43 +++++++++++-------- .../Conditions/DataModelConditionPredicate.cs | 4 +- .../ListPredicateWrapperDataModel.cs | 6 +++ .../DataModelListPropertiesViewModel.cs | 25 ++++++----- .../Shared/DataModelListPropertyViewModel.cs | 16 +++---- .../Shared/DataModelListViewModel.cs | 25 +++++------ .../Shared/DataModelVisualizationViewModel.cs | 10 ++--- ...ataModelConditionListPredicateViewModel.cs | 26 +++++------ .../Debug/Tabs/DataModelDebugView.xaml | 2 +- 10 files changed, 91 insertions(+), 75 deletions(-) diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs index 60739c2b5..7b7a45919 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs @@ -96,8 +96,8 @@ namespace Artemis.Core throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{newPath}'"); ListPath = newPath; - ListType = listType; - IsPrimitiveList = listType.IsPrimitive || listType.IsEnum || listType == typeof(string); + ListType = listType.GetGenericArguments()[0]; + IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string); } else { @@ -182,10 +182,13 @@ namespace Artemis.Core // Ensure the list path is valid and points to a list DataModelPath listPath = new DataModelPath(null, Entity.ListPath); - if (!listPath.IsValid || !typeof(IList).IsAssignableFrom(listPath.GetPropertyType())) + Type listType = listPath.GetPropertyType()!; + if (!listPath.IsValid || !typeof(IList).IsAssignableFrom(listType)) return; ListPath = listPath; + ListType = listType.GetGenericArguments()[0]; + IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string); // There should only be one child and it should be a group if (Entity.Children.SingleOrDefault() is DataModelConditionGroupEntity rootGroup) diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs index f7e484254..628ccfe9e 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs @@ -70,18 +70,17 @@ namespace Artemis.Core /// Updates the left side of the predicate /// /// The path pointing to the left side value inside the list - public void UpdateLeftSide(string path) + public void UpdateLeftSide(string? path) { if (DataModelConditionList.IsPrimitiveList) throw new ArtemisCoreException("Cannot apply a left side to a predicate inside a primitive list"); - if (!ListContainsInnerPath(path)) - throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}"); LeftPath?.Dispose(); - LeftPath = DataModelConditionList.ListType != null - ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path) - : null; - + if (path != null && DataModelConditionList.ListType != null) + LeftPath = new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path); + else + LeftPath = null; + ValidateOperator(); ValidateRightSide(); } @@ -91,16 +90,15 @@ namespace Artemis.Core /// and re-compiles the expression /// /// The path pointing to the right side value inside the list - public void UpdateRightSideDynamic(string path) + public void UpdateRightSideDynamic(string? path) { - if (!ListContainsInnerPath(path)) - throw new ArtemisCoreException($"List type {DataModelConditionList.ListType.Name} does not contain path {path}"); + RightPath?.Dispose(); + if (path != null && DataModelConditionList.ListType != null) + RightPath = new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path); + else + RightPath = null; PredicateType = ListRightSideType.DynamicList; - RightPath?.Dispose(); - RightPath = DataModelConditionList.ListType != null - ? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path) - : null; } /// @@ -109,20 +107,27 @@ namespace Artemis.Core /// /// /// The path pointing to the right side value inside the list - public void UpdateRightSideDynamic(DataModel dataModel, string path) + public void UpdateRightSideDynamic(DataModel? dataModel, string? path) { if (dataModel != null && path == null) throw new ArtemisCoreException("If a data model is provided, a path is also required"); if (dataModel == null && path != null) throw new ArtemisCoreException("If path is provided, a data model is also required"); + RightPath?.Dispose(); if (dataModel != null) - if (!dataModel.ContainsPath(path)) - throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'"); + { + DataModelPath newPath = new DataModelPath(dataModel, path); + if (!newPath.IsValid) + throw new ArtemisCoreException($"New right path '{newPath}' is invalid"); + RightPath = newPath; + } + else + { + RightPath = null; + } PredicateType = ListRightSideType.Dynamic; - RightPath?.Dispose(); - RightPath = new DataModelPath(dataModel, path); } /// diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs index 601bea3ff..12e7a5b6f 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs @@ -76,7 +76,7 @@ namespace Artemis.Core throw new ArtemisCoreException("If path is provided, a data model is also required"); LeftPath?.Dispose(); - if (dataModel != null && path != null) + if (dataModel != null) { DataModelPath newPath = new DataModelPath(dataModel, path); if (!newPath.IsValid) @@ -105,7 +105,7 @@ namespace Artemis.Core throw new ArtemisCoreException("If path is provided, a data model is also required"); RightPath?.Dispose(); - if (dataModel != null && path != null) + if (dataModel != null) { DataModelPath newPath = new DataModelPath(dataModel, path); if (!newPath.IsValid) diff --git a/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs index e134b5dc8..884dd77c0 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/ListPredicateWrapperDataModel.cs @@ -10,6 +10,12 @@ namespace Artemis.Core public abstract class ListPredicateWrapperDataModel : DataModel { + internal ListPredicateWrapperDataModel() + { + PluginInfo = Constants.CorePluginInfo; + } + + [DataModelIgnore] public object? UntypedValue { get; set; } public static ListPredicateWrapperDataModel Create(Type type) diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs index 6d6afaa64..0eca0e386 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Artemis.Core; using Artemis.UI.Shared.Services; @@ -10,11 +11,12 @@ namespace Artemis.UI.Shared private int _index; private Type _listType; - public DataModelListPropertiesViewModel(object listItem) : base(null, null, null) + public DataModelListPropertiesViewModel(Type listType) : base(null, null, null) { - DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType()); - ListType = listItem.GetType(); - DisplayValue = listItem; + DataModel = ListPredicateWrapperDataModel.Create(listType); + ListType = listType; + + IsRootViewModel = false; } public int Index @@ -35,18 +37,21 @@ namespace Artemis.UI.Shared set => SetAndNotify(ref _displayValue, value); } + public DataModelVisualizationViewModel DisplayViewModel => Children.FirstOrDefault(); + public override string DisplayPath => null; public override void Update(IDataModelUIService dataModelUIService) { - // Display value gets updated by parent, don't do anything if it is null - if (DisplayValue == null) + ((ListPredicateWrapperDataModel) DataModel).UntypedValue = DisplayValue; + + PopulateProperties(dataModelUIService); + if (DisplayViewModel == null) return; - ListType = DisplayValue.GetType(); - PopulateProperties(dataModelUIService); - foreach (DataModelVisualizationViewModel dataModelVisualizationViewModel in Children) - dataModelVisualizationViewModel.Update(dataModelUIService); + if (IsVisualizationExpanded && !DisplayViewModel.IsVisualizationExpanded) + DisplayViewModel.IsVisualizationExpanded = IsVisualizationExpanded; + DisplayViewModel.Update(dataModelUIService); } public override object GetCurrentValue() diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs index db47e9f7a..42767fd67 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertyViewModel.cs @@ -9,19 +9,17 @@ namespace Artemis.UI.Shared private int _index; private Type _listType; - public DataModelListPropertyViewModel(object listItem, DataModelDisplayViewModel displayViewModel) : base(null, null, null) + public DataModelListPropertyViewModel(Type listType, DataModelDisplayViewModel displayViewModel) : base(null, null, null) { - DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType()); - ListType = listItem.GetType(); - DisplayValue = listItem; + DataModel = ListPredicateWrapperDataModel.Create(listType); + ListType = listType; DisplayViewModel = displayViewModel; } - public DataModelListPropertyViewModel(object listItem) : base(null, null, null) + public DataModelListPropertyViewModel(Type listType) : base(null, null, null) { - DataModel = ListPredicateWrapperDataModel.Create(listItem.GetType()); - ListType = listItem.GetType(); - DisplayValue = listItem; + DataModel = ListPredicateWrapperDataModel.Create(listType); + ListType = listType; } public int Index @@ -47,6 +45,8 @@ namespace Artemis.UI.Shared if (DisplayValue == null) return; + ((ListPredicateWrapperDataModel)DataModel).UntypedValue = DisplayValue; + if (DisplayViewModel == null) DisplayViewModel = dataModelUIService.GetDataModelDisplayViewModel(DisplayValue.GetType(), true); diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs index 28c483320..c4c337e96 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListViewModel.cs @@ -33,19 +33,19 @@ namespace Artemis.UI.Shared public DataModelPropertiesViewModel GetListTypeViewModel(IDataModelUIService dataModelUIService) { - Type type = DataModelPath.GetPropertyType(); - if (type == null) + Type listType = DataModelPath.GetPropertyType()?.GenericTypeArguments[0]; + if (listType == null) return null; // Create a property VM describing the type of the list - DataModelVisualizationViewModel viewModel = CreateListChild(dataModelUIService, type.GenericTypeArguments[0]); + DataModelVisualizationViewModel viewModel = CreateListChild(dataModelUIService, listType); + viewModel.Update(dataModelUIService); // Put an empty value into the list type property view model if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel) { return dataModelListClassViewModel; } - if (viewModel is DataModelListPropertyViewModel dataModelListPropertyViewModel) { dataModelListPropertyViewModel.DisplayValue = Activator.CreateInstance(dataModelListPropertyViewModel.ListType); @@ -67,12 +67,15 @@ namespace Artemis.UI.Shared return; int index = 0; - foreach (object? item in List) + foreach (object item in List) { + if (item == null) + continue; + DataModelVisualizationViewModel child; if (ListChildren.Count <= index) { - child = CreateListChild(dataModelUIService, item); + child = CreateListChild(dataModelUIService, item.GetType()); ListChildren.Add(child); } else @@ -99,20 +102,18 @@ namespace Artemis.UI.Shared Count = $"{ListChildren.Count} {(ListChildren.Count == 1 ? "item" : "items")}"; } - protected DataModelVisualizationViewModel CreateListChild(IDataModelUIService dataModelUIService, object listItem) + protected DataModelVisualizationViewModel CreateListChild(IDataModelUIService dataModelUIService, Type listType) { - Type listType = listItem.GetType(); - // If a display VM was found, prefer to use that in any case DataModelDisplayViewModel typeViewModel = dataModelUIService.GetDataModelDisplayViewModel(listType); if (typeViewModel != null) - return new DataModelListPropertyViewModel(listItem, typeViewModel); + return new DataModelListPropertyViewModel(listType, typeViewModel); // For primitives, create a property view model, it may be null that is fine if (listType.IsPrimitive || listType.IsEnum || listType == typeof(string)) - return new DataModelListPropertyViewModel(listItem); + return new DataModelListPropertyViewModel(listType); // For other value types create a child view model if (listType.IsClass || listType.IsStruct()) - return new DataModelListPropertiesViewModel(listItem); + return new DataModelListPropertiesViewModel(listType); return null; } diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs index 67651698f..69faf8fe0 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs @@ -35,7 +35,7 @@ namespace Artemis.UI.Shared PropertyDescription = DataModelPath?.GetPropertyDescription() ?? DataModel.DataModelDescription; } - public bool IsRootViewModel { get; } + public bool IsRootViewModel { get; protected set; } public DataModelPath DataModelPath { get; } public string Path => DataModelPath?.Path; @@ -81,7 +81,7 @@ namespace Artemis.UI.Shared } } - public virtual string DisplayPath => Path?.Replace(".", " › "); + public virtual string DisplayPath => string.Join(" › ", DataModelPath.Segments.Select(s => s.GetPropertyDescription()?.Name ?? s.Identifier)); /// /// Updates the datamodel and if in an parent, any children @@ -146,7 +146,7 @@ namespace Artemis.UI.Shared return null; if (propertyPath == null) return null; - if (Path.StartsWith(propertyPath, StringComparison.OrdinalIgnoreCase)) + if (Path != null && Path.StartsWith(propertyPath, StringComparison.OrdinalIgnoreCase)) return null; } @@ -183,7 +183,7 @@ namespace Artemis.UI.Shared if (IsRootViewModel) return; - Type modelType = Parent.IsRootViewModel ? DataModel.GetType() : DataModelPath.GetPropertyType(); + Type modelType = Parent == null || Parent.IsRootViewModel ? DataModel.GetType() : DataModelPath.GetPropertyType(); // Add missing static children foreach (PropertyInfo propertyInfo in modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) @@ -210,7 +210,7 @@ namespace Artemis.UI.Shared } // Add missing dynamic children - object value = Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue(); + object value = Parent == null || Parent.IsRootViewModel ? DataModel : DataModelPath.GetValue(); if (value is DataModel dataModel) { foreach (KeyValuePair kvp in dataModel.DynamicDataModels) diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs index fe0c16bb0..b1286e616 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs @@ -117,10 +117,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions if (!_isPrimitiveList) { - LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); + // Lists use a different color LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188)); - LeftSideSelectionViewModel.SelectedPropertyViewModel = LeftSideSelectionViewModel.DataModelViewModel.GetChildByPath( - listDataModelGuid.Value, DataModelConditionListPredicate.DataModelConditionList.ListPath.Path + LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); + LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel( + DataModelConditionListPredicate.LeftPath?.Target, + DataModelConditionListPredicate.LeftPath?.Path ); } @@ -141,9 +143,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions } // Ensure the right side has the proper VM - if ((DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic || - DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) && - SelectedOperator.SupportsRightSide) + ListRightSideType type = DataModelConditionListPredicate.PredicateType; + if ((type == ListRightSideType.Dynamic || type == ListRightSideType.DynamicList) && SelectedOperator.SupportsRightSide) { DisposeRightSideStatic(); if (RightSideSelectionViewModel == null) @@ -157,15 +158,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions } RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; - if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) - RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( - DataModelConditionListPredicate.RightPath?.Target, - DataModelConditionListPredicate.RightPath?.Path - ); - else - RightSideSelectionViewModel.SelectedPropertyViewModel = RightSideSelectionViewModel.DataModelViewModel.GetChildByPath( - listDataModelGuid.Value, DataModelConditionListPredicate.RightPath?.Path - ); + RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( + DataModelConditionListPredicate.RightPath?.Target, + DataModelConditionListPredicate.RightPath?.Path + ); } else if (SelectedOperator.SupportsRightSide) { diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml index c15419957..f7051ca0f 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml +++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugView.xaml @@ -117,7 +117,7 @@ - + List item []