diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs index 7b7a45919..c09736df7 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionList.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Artemis.Core.DataModelExpansions; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; @@ -73,47 +72,36 @@ namespace Artemis.Core /// /// Updates the list the predicate is evaluated on /// - /// The data model of the list /// The path pointing to the list inside the list - public void UpdateList(DataModel? dataModel, string? path) + public void UpdateList(DataModelPath? path) { if (_disposed) throw new ObjectDisposedException("DataModelConditionList"); - 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"); + if (path != null && !path.IsValid) + throw new ArtemisCoreException("Cannot update list to an invalid path"); ListPath?.Dispose(); - if (dataModel != null && path != null) - { - DataModelPath newPath = new DataModelPath(dataModel, path); - if (!newPath.IsValid) - throw new ArtemisCoreException($"New left path '{newPath}' is invalid"); - Type listType = newPath.GetPropertyType()!; - if (!typeof(IList).IsAssignableFrom(listType)) - throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{newPath}'"); + ListPath = path; - ListPath = newPath; + // Remove the old root group that was tied to the old data model + while (Children.Any()) + RemoveChild(Children[0]); + + if (path != null) + { + Type listType = path.GetPropertyType()!; ListType = listType.GetGenericArguments()[0]; IsPrimitiveList = ListType.IsPrimitive || ListType.IsEnum || ListType == typeof(string); + + // Create a new root group + AddChild(new DataModelConditionGroup(this)); } else { ListPath = null; ListType = null; } - - // Remove the old root group that was tied to the old data model - while (Children.Any()) - RemoveChild(Children[0]); - - if (dataModel == null) - return; - - // Create a new root group - AddChild(new DataModelConditionGroup(this)); } #region IDisposable diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs index 628ccfe9e..e53b29698 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs @@ -90,13 +90,10 @@ 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 UpdateRightSideDynamicList(DataModelPath? path) { RightPath?.Dispose(); - if (path != null && DataModelConditionList.ListType != null) - RightPath = new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), path); - else - RightPath = null; + RightPath = path; PredicateType = ListRightSideType.DynamicList; } @@ -105,27 +102,11 @@ namespace Artemis.Core /// Updates the right side of the predicate using path to a value in a data model, makes the predicate dynamic and /// re-compiles the expression /// - /// /// The path pointing to the right side value inside the list - public void UpdateRightSideDynamic(DataModel? dataModel, string? path) + public void UpdateRightSideDynamic(DataModelPath? 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) - { - DataModelPath newPath = new DataModelPath(dataModel, path); - if (!newPath.IsValid) - throw new ArtemisCoreException($"New right path '{newPath}' is invalid"); - RightPath = newPath; - } - else - { - RightPath = null; - } + RightPath = path; PredicateType = ListRightSideType.Dynamic; } @@ -391,7 +372,7 @@ namespace Artemis.Core Type rightSideType = RightPath.GetPropertyType()!; if (leftType != null && !leftType.IsCastableFrom(rightSideType)) - UpdateRightSideDynamic(null, null); + UpdateRightSideDynamic(null); } else if (PredicateType == ListRightSideType.DynamicList) { @@ -400,7 +381,7 @@ namespace Artemis.Core Type rightSideType = RightPath.GetPropertyType()!; if (leftType != null && !leftType.IsCastableFrom(rightSideType)) - UpdateRightSideDynamic(null); + UpdateRightSideDynamicList(null); } else { diff --git a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs index ec6b96e23..8b29c8ea6 100644 --- a/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs +++ b/src/Artemis.Core/Models/Profile/DataBindings/Modes/DataBindingModifier.cs @@ -190,7 +190,7 @@ namespace Artemis.Core /// /// The data model of the parameter /// The path pointing to the parameter inside the data model - public void UpdateParameter(DataModel dataModel, string path) + public void UpdateParameter(DataModel? dataModel, string? path) { if (_disposed) throw new ObjectDisposedException("DataBindingModifier"); diff --git a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs index d28d6b0b7..b98fcdcb4 100644 --- a/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs +++ b/src/Artemis.Core/Models/Profile/DataModel/DataModelPath.cs @@ -65,6 +65,19 @@ namespace Artemis.Core SubscribeToDataModelStore(); } + internal DataModelPath(DataModelPath dataModelPath) + { + Target = dataModelPath.Target; + Path = dataModelPath.Path; + Entity = new DataModelPathEntity(); + + _segments = new LinkedList(); + + Save(); + Initialize(); + SubscribeToDataModelStore(); + } + /// /// Gets the data model at which this path starts /// diff --git a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs index dcb800f08..3b0be36e6 100644 --- a/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs +++ b/src/Artemis.Core/Plugins/DataModelExpansions/DataModel.cs @@ -137,10 +137,12 @@ namespace Artemis.Core.DataModelExpansions return value as T; } - internal bool ContainsPath(string path) + internal bool ContainsPath(string? path) { + if (path == null) + return false; string[] parts = path.Split('.'); - Type current = GetType(); + Type? current = GetType(); foreach (string part in parts) { PropertyInfo? property = current?.GetProperty(part); diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml index b260726fc..972cb9c74 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicView.xaml @@ -50,10 +50,10 @@ - + + Visibility="{Binding DataModelPath, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}"> diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs index 71474d996..be37a3ad5 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Input/DataModelDynamicViewModel.cs @@ -1,8 +1,8 @@ using System; +using System.Linq; using System.Timers; using System.Windows.Media; using Artemis.Core; -using Artemis.Core.DataModelExpansions; using Artemis.Core.Modules; using Artemis.Core.Services; using Artemis.UI.Shared.Services; @@ -19,12 +19,12 @@ namespace Artemis.UI.Shared.Input private readonly Module _module; private readonly Timer _updateTimer; private Brush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188)); + private DataModelPath _dataModelPath; private DataModelPropertiesViewModel _dataModelViewModel; + private Type[] _filterTypes; private bool _isDataModelViewModelOpen; private bool _isEnabled = true; private string _placeholder = "Select a property"; - private DataModelVisualizationViewModel _selectedPropertyViewModel; - private Type[] _filterTypes; internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService) { @@ -81,19 +81,17 @@ namespace Artemis.UI.Shared.Input set => SetAndNotify(ref _isDataModelViewModelOpen, value); } - public DataModelVisualizationViewModel SelectedPropertyViewModel + public DataModelPath DataModelPath { - get => _selectedPropertyViewModel; - set => SetAndNotify(ref _selectedPropertyViewModel, value); + private get => _dataModelPath; + set + { + if (!SetAndNotify(ref _dataModelPath, value)) return; + NotifyOfPropertyChange(nameof(DisplayValue)); + } } - public void PopulateSelectedPropertyViewModel(DataModel datamodel, string path) - { - if (datamodel == null) - SelectedPropertyViewModel = null; - else - SelectedPropertyViewModel = DataModelViewModel.GetChildByPath(datamodel.PluginInfo.Guid, path); - } + public string DisplayValue => DataModelPath.GetPropertyDescription()?.Name ?? DataModelPath.Segments.LastOrDefault()?.Identifier; public void ChangeDataModel(DataModelPropertiesViewModel dataModel) { @@ -132,10 +130,16 @@ namespace Artemis.UI.Shared.Input if (!(context is DataModelVisualizationViewModel selected)) return; - SelectedPropertyViewModel = selected; - OnPropertySelected(new DataModelInputDynamicEventArgs(selected)); + DataModelPath = selected.DataModelPath; + OnPropertySelected(new DataModelInputDynamicEventArgs(DataModelPath)); } + public void Dispose() + { + _updateTimer.Stop(); + _updateTimer.Dispose(); + _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; + } #region Events @@ -147,12 +151,5 @@ namespace Artemis.UI.Shared.Input } #endregion - - public void Dispose() - { - _updateTimer.Stop(); - _updateTimer.Dispose(); - _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; - } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Events/DataModelInputDynamicEventArgs.cs b/src/Artemis.UI.Shared/Events/DataModelInputDynamicEventArgs.cs index 9f7649dbb..02a411427 100644 --- a/src/Artemis.UI.Shared/Events/DataModelInputDynamicEventArgs.cs +++ b/src/Artemis.UI.Shared/Events/DataModelInputDynamicEventArgs.cs @@ -1,14 +1,15 @@ using System; +using Artemis.Core; namespace Artemis.UI.Shared { public class DataModelInputDynamicEventArgs : EventArgs { - public DataModelVisualizationViewModel DataModelVisualizationViewModel { get; } + public DataModelPath DataModelPath { get; } - public DataModelInputDynamicEventArgs(DataModelVisualizationViewModel dataModelVisualizationViewModel) + public DataModelInputDynamicEventArgs(DataModelPath dataModelPath) { - DataModelVisualizationViewModel = dataModelVisualizationViewModel; + DataModelPath = dataModelPath; } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs index b1286e616..108e7f21b 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs @@ -120,15 +120,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions // Lists use a different color LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188)); LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray(); - LeftSideSelectionViewModel.PopulateSelectedPropertyViewModel( - DataModelConditionListPredicate.LeftPath?.Target, - DataModelConditionListPredicate.LeftPath?.Path - ); + LeftSideSelectionViewModel.DataModelPath = DataModelConditionListPredicate.LeftPath; } Type leftSideType = _isPrimitiveList ? DataModelConditionListPredicate.DataModelConditionList.ListType - : LeftSideSelectionViewModel.SelectedPropertyViewModel?.DataModelPath?.GetPropertyType(); + : LeftSideSelectionViewModel.DataModelPath?.GetPropertyType(); // Get the supported operators Operators.Clear(); @@ -158,10 +155,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions } RightSideSelectionViewModel.FilterTypes = new[] {leftSideType}; - RightSideSelectionViewModel.PopulateSelectedPropertyViewModel( - DataModelConditionListPredicate.RightPath?.Target, - DataModelConditionListPredicate.RightPath?.Path - ); + LeftSideSelectionViewModel.DataModelPath = DataModelConditionListPredicate.RightPath; } else if (SelectedOperator.SupportsRightSide) { @@ -181,7 +175,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void ApplyLeftSide() { - DataModelConditionListPredicate.UpdateLeftSide(LeftSideSelectionViewModel.SelectedPropertyViewModel.Path); + DataModelConditionListPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath.Path); _profileEditorService.UpdateSelectedProfileElement(); SelectedOperator = DataModelConditionListPredicate.Operator; @@ -191,12 +185,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void ApplyRightSideDynamic() { if (DataModelConditionListPredicate.PredicateType == ListRightSideType.Dynamic) - DataModelConditionListPredicate.UpdateRightSideDynamic( - RightSideSelectionViewModel.SelectedPropertyViewModel.DataModel, - RightSideSelectionViewModel.SelectedPropertyViewModel.Path - ); + DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath); else if (DataModelConditionListPredicate.PredicateType == ListRightSideType.DynamicList) - DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.SelectedPropertyViewModel.Path); + DataModelConditionListPredicate.UpdateRightSideDynamicList(RightSideSelectionViewModel.DataModelPath); _profileEditorService.UpdateSelectedProfileElement(); Update(); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs index 36144400a..93fefcbad 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs @@ -96,10 +96,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public void ApplyList() { - DataModelConditionList.UpdateList( - TargetSelectionViewModel.SelectedPropertyViewModel.DataModel, - TargetSelectionViewModel.SelectedPropertyViewModel.Path - ); + DataModelConditionList.UpdateList(TargetSelectionViewModel.DataModelPath); _profileEditorService.UpdateSelectedProfileElement(); Update(); @@ -107,7 +104,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions public override void Update() { - TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DataModelConditionList.ListPath?.Target, DataModelConditionList.ListPath?.Path); + TargetSelectionViewModel.DataModelPath = DataModelConditionList.ListPath; NotifyOfPropertyChange(nameof(SelectedListOperator)); // Remove VMs of effects no longer applied on the layer diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DirectDataBinding/DataBindingModifierViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DirectDataBinding/DataBindingModifierViewModel.cs index a2d4eea65..52996caa4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DirectDataBinding/DataBindingModifierViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/DataBindings/DirectDataBinding/DataBindingModifierViewModel.cs @@ -105,7 +105,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa private void ParameterSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) { - Modifier.UpdateParameter(e.DataModelVisualizationViewModel.DataModel, e.DataModelVisualizationViewModel.Path); + Modifier.UpdateParameter(e.DataModelPath.Target, e.DataModelPath.Path); _profileEditorService.UpdateSelectedProfileElement(); }