diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs index aa92c2476..c4529322f 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs @@ -35,7 +35,7 @@ namespace Artemis.Core.Models.Profile.Conditions public override void ApplyToEntity() { DisplayConditionGroupEntity.Id = EntityId; - DisplayConditionGroupEntity.ParentId = Parent?.EntityId ?? new Guid(); + DisplayConditionGroupEntity.ParentId = Parent?.EntityId ?? Guid.Empty; DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator; foreach (var child in Children) diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs index 38e8e4705..40d379ef6 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs @@ -6,6 +6,10 @@ namespace Artemis.Core.Models.Profile.Conditions { public ListOperator ListOperator { get; set; } + public override void ApplyToEntity() + { + + } } public enum ListOperator diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs index 8dca8a826..458ffb4ee 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionPredicate.cs @@ -11,9 +11,10 @@ namespace Artemis.Core.Models.Profile.Conditions { public class DisplayConditionPredicate : DisplayConditionPart { - public DisplayConditionPredicate(DisplayConditionPart parent) + public DisplayConditionPredicate(DisplayConditionPart parent, PredicateType predicateType) { Parent = parent; + PredicateType = predicateType; DisplayConditionPredicateEntity = new DisplayConditionPredicateEntity(); } @@ -30,7 +31,7 @@ namespace Artemis.Core.Models.Profile.Conditions public DisplayConditionPredicateEntity DisplayConditionPredicateEntity { get; set; } public PredicateType PredicateType { get; set; } - public DisplayConditionOperator Operator { get; set; } + public DisplayConditionOperator Operator { get; private set; } public DataModel LeftDataModel { get; private set; } public string LeftPropertyPath { get; private set; } @@ -45,20 +46,37 @@ namespace Artemis.Core.Models.Profile.Conditions public void UpdateLeftSide(DataModel dataModel, string path) { - if (!dataModel.ContainsPath(path)) - throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{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"); + + 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}'"); + } LeftDataModel = dataModel; LeftPropertyPath = path; + ValidateOperator(); ValidateRightSide(); CreateExpression(); } public void UpdateRightSide(DataModel dataModel, string path) { - if (!dataModel.ContainsPath(path)) - throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{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"); + + 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}'"); + } PredicateType = PredicateType.Dynamic; RightDataModel = dataModel; @@ -77,6 +95,25 @@ namespace Artemis.Core.Models.Profile.Conditions CreateExpression(); } + public void UpdateOperator(DisplayConditionOperator displayConditionOperator) + { + if (displayConditionOperator == null) + { + Operator = null; + return; + } + + if (LeftDataModel == null) + { + Operator = displayConditionOperator; + return; + } + + var leftType = LeftDataModel.GetTypeAtPath(LeftPropertyPath); + if (displayConditionOperator.SupportsType(leftType)) + Operator = displayConditionOperator; + } + public void CreateExpression() { if (PredicateType == PredicateType.Dynamic) @@ -89,6 +126,17 @@ namespace Artemis.Core.Models.Profile.Conditions { } + private void ValidateOperator() + { + if (LeftDataModel == null) + return; + + var leftType = LeftDataModel.GetTypeAtPath(LeftPropertyPath); + if (!Operator.SupportsType(leftType)) + Operator = null; + } + + /// /// Validates the right side, ensuring it is still compatible with the current left side /// @@ -97,14 +145,19 @@ namespace Artemis.Core.Models.Profile.Conditions var leftSideType = LeftDataModel.GetTypeAtPath(LeftPropertyPath); if (PredicateType == PredicateType.Dynamic) { + if (RightDataModel == null) + return; + var rightSideType = RightDataModel.GetTypeAtPath(RightPropertyPath); if (!leftSideType.IsCastableFrom(rightSideType)) UpdateRightSide(null, null); } else { - // Just update the value with itself, it'll validate :) - UpdateRightSide(RightStaticValue); + if (RightStaticValue != null && leftSideType.IsCastableFrom(RightStaticValue.GetType())) + UpdateRightSide(RightStaticValue); + else + UpdateRightSide(null); } } diff --git a/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs index 24931edc3..cb1bbcb00 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/DataModelInputViewModel.cs @@ -1,18 +1,17 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Input; using Artemis.Core.Plugins.Abstract.DataModels.Attributes; -using Artemis.UI.Shared.Exceptions; using Stylet; namespace Artemis.UI.Shared.DataModelVisualization { public abstract class DataModelInputViewModel : DataModelInputViewModel { + private bool _closed; private T _inputValue; protected DataModelInputViewModel(DataModelPropertyAttribute description, T initialValue) @@ -33,6 +32,10 @@ namespace Artemis.UI.Shared.DataModelVisualization /// public sealed override void Submit() { + if (_closed) + return; + _closed = true; + foreach (var sourceUpdatingBinding in BindingOperations.GetSourceUpdatingBindings(View)) sourceUpdatingBinding.UpdateSource(); @@ -43,6 +46,10 @@ namespace Artemis.UI.Shared.DataModelVisualization /// public sealed override void Cancel() { + if (_closed) + return; + _closed = true; + OnCancel(); UpdateCallback(InputValue, false); } @@ -62,7 +69,8 @@ namespace Artemis.UI.Shared.DataModelVisualization internal Action UpdateCallback { get; set; } /// - /// Gets the types this input view model can support through type conversion. This list is defined when registering the view model. + /// Gets the types this input view model can support through type conversion. This list is defined when registering the + /// view model. /// internal IReadOnlyCollection CompatibleConversionTypes { get; set; } @@ -84,12 +92,14 @@ namespace Artemis.UI.Shared.DataModelVisualization public UIElement View { get; set; } /// - /// Submits the input value and removes this view model + /// Submits the input value and removes this view model. + /// This is called automatically when the user presses enter or clicks outside the view /// public abstract void Submit(); /// - /// Discards changes to the input value and removes this view model + /// Discards changes to the input value and removes this view model. + /// This is called automatically when the user presses escape /// public abstract void Cancel(); diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs index cc1042542..c710a86b1 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Linq; using System.Reflection; using Artemis.Core.Extensions; @@ -18,10 +17,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared { private BindableCollection _children; private DataModel _dataModel; + private bool _isMatchingFilteredTypes; private DataModelVisualizationViewModel _parent; private DataModelPropertyAttribute _propertyDescription; private PropertyInfo _propertyInfo; - private bool _isMatchingFilteredTypes; internal DataModelVisualizationViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, PropertyInfo propertyInfo) { @@ -75,6 +74,36 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared set => SetAndNotify(ref _isMatchingFilteredTypes, value); } + public string PropertyPath + { + get + { + if (Parent == null) + return PropertyInfo?.Name; + + if (PropertyInfo == null) + return Parent.PropertyPath; + + var parentPath = Parent.PropertyPath; + return parentPath != null ? $"{parentPath}.{PropertyInfo.Name}" : PropertyInfo.Name; + } + } + + public string DisplayPropertyPath + { + get + { + if (Parent == null) + return PropertyDescription?.Name; + + if (PropertyDescription == null) + return Parent.DisplayPropertyPath; + + var parentPath = Parent.DisplayPropertyPath; + return parentPath != null ? $"{parentPath} › {PropertyDescription.Name}" : PropertyDescription.Name; + } + } + public abstract void Update(IDataModelVisualizationService dataModelVisualizationService); public virtual object GetCurrentValue() @@ -84,6 +113,14 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared public void ApplyTypeFilter(bool looseMatch, params Type[] filteredTypes) { + if (filteredTypes != null) + { + if (filteredTypes.All(t => t == null)) + filteredTypes = null; + else + filteredTypes = filteredTypes.Where(t => t != null).ToArray(); + } + // If the VM has children, its own type is not relevant if (Children.Any()) { @@ -114,9 +151,18 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared IsMatchingFilteredTypes = filteredTypes.Any(t => t == PropertyInfo.PropertyType); } - public DataModelVisualizationViewModel GetChildForCondition(DisplayConditionPredicate predicate) + public DataModelVisualizationViewModel GetChildForCondition(DisplayConditionPredicate predicate, DisplayConditionSide side) { + if (side == DisplayConditionSide.Left) + { + if (predicate.LeftDataModel == null || predicate.LeftPropertyPath == null) + return null; + return GetChildByPath(predicate.LeftDataModel.PluginInfo.Guid, predicate.LeftPropertyPath); + } + if (predicate.RightDataModel == null || predicate.RightPropertyPath == null) + return null; + return GetChildByPath(predicate.RightDataModel.PluginInfo.Guid, predicate.RightPropertyPath); } public DataModelVisualizationViewModel GetChildByPath(Guid dataModelGuid, string propertyPath) @@ -141,18 +187,6 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared } } - public string GetCurrentPath() - { - if (Parent == null) - return PropertyInfo?.Name; - - if (PropertyInfo == null) - return Parent.GetCurrentPath(); - - var parentPath = Parent.GetCurrentPath(); - return parentPath != null ? $"{parentPath}.{PropertyInfo.Name}" : PropertyInfo.Name; - } - protected DataModelVisualizationViewModel CreateChild(IDataModelVisualizationService dataModelVisualizationService, PropertyInfo propertyInfo) { // Skip properties decorated with DataModelIgnore @@ -182,8 +216,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared PropertyDescription = DataModel?.DataModelDescription; // Rely on property info for the description else if (PropertyInfo != null) + { PropertyDescription = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(PropertyInfo, typeof(DataModelPropertyAttribute)) ?? new DataModelPropertyAttribute {Name = PropertyInfo.Name.Humanize()}; + } else throw new ArtemisSharedUIException("Failed to get property description because plugin info is null but the parent has a datamodel"); @@ -192,4 +228,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared PropertyDescription.Name = PropertyInfo.Name.Humanize(); } } + + public enum DisplayConditionSide + { + Left, + Right + } } \ No newline at end of file diff --git a/src/Artemis.UI/DataModelVisualization/Input/DoubleDataModelInputView.xaml b/src/Artemis.UI/DataModelVisualization/Input/DoubleDataModelInputView.xaml index 5f8a5dce0..7b55d7071 100644 --- a/src/Artemis.UI/DataModelVisualization/Input/DoubleDataModelInputView.xaml +++ b/src/Artemis.UI/DataModelVisualization/Input/DoubleDataModelInputView.xaml @@ -8,7 +8,7 @@ xmlns:s="https://github.com/canton7/Stylet" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - + diff --git a/src/Artemis.UI/DataModelVisualization/Input/IntDataModelInputView.xaml b/src/Artemis.UI/DataModelVisualization/Input/IntDataModelInputView.xaml index 6f36a7116..856747483 100644 --- a/src/Artemis.UI/DataModelVisualization/Input/IntDataModelInputView.xaml +++ b/src/Artemis.UI/DataModelVisualization/Input/IntDataModelInputView.xaml @@ -8,7 +8,7 @@ xmlns:s="https://github.com/canton7/Stylet" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - + diff --git a/src/Artemis.UI/DataModelVisualization/Input/StringDataModelInputView.xaml b/src/Artemis.UI/DataModelVisualization/Input/StringDataModelInputView.xaml index a184aad11..df27adb53 100644 --- a/src/Artemis.UI/DataModelVisualization/Input/StringDataModelInputView.xaml +++ b/src/Artemis.UI/DataModelVisualization/Input/StringDataModelInputView.xaml @@ -5,9 +5,10 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:b="http://schemas.microsoft.com/xaml/behaviors" xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors;assembly=Artemis.UI.Shared" + xmlns:s="https://github.com/canton7/Stylet" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> - + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs index 3884102fc..8198d49a7 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs @@ -38,15 +38,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions public void AddCondition(string type) { if (type == "Static") - DisplayConditionGroup.AddChild(new DisplayConditionPredicate {PredicateType = PredicateType.Static}); + DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static)); else if (type == "Dynamic") - DisplayConditionGroup.AddChild(new DisplayConditionPredicate {PredicateType = PredicateType.Dynamic}); + DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic)); Update(); } public void AddGroup() { - DisplayConditionGroup.AddChild(new DisplayConditionGroup()); + DisplayConditionGroup.AddChild(new DisplayConditionGroup(DisplayConditionGroup)); Update(); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionPredicateView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionPredicateView.xaml index 415886906..d20afb360 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionPredicateView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionPredicateView.xaml @@ -48,7 +48,7 @@ Background="#ab47bc" BorderBrush="#ab47bc" Style="{StaticResource DisplayConditionButton}" - ToolTip="{Binding DisplayConditionPredicate.LeftPropertyPath}" + ToolTip="{Binding SelectedLeftSideProperty.DisplayPropertyPath}" Click="PropertyButton_OnClick"> @@ -80,7 +80,7 @@ Style="{StaticResource DisplayConditionButtonLeftClickMenu}" Background="#7B7B7B" BorderBrush="#7B7B7B" - Content="{Binding DisplayConditionPredicate.Operator.Description}" + Content="{Binding SelectedOperator.Description}" Click="PropertyButton_OnClick"> @@ -109,7 +109,7 @@ Background="{DynamicResource PrimaryHueMidBrush}" BorderBrush="{DynamicResource PrimaryHueMidBrush}" Style="{StaticResource DisplayConditionButton}" - ToolTip="{Binding DisplayConditionPredicate.RightPropertyPath}" + ToolTip="{Binding SelectedRightSideProperty.DisplayPropertyPath}" Click="PropertyButton_OnClick" Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"> @@ -147,12 +147,12 @@ Command="{s:Action ActivateRightSideInputViewModel}" HorizontalAlignment="Left"> - + - + + Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" /> _supportedInputTypes; + private object _rightStaticValue; public DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent, IProfileEditorService profileEditorService, IDataModelVisualizationService dataModelVisualizationService, IDataModelService dataModelService, IEventAggregator eventAggregator) @@ -46,7 +48,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty); SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand); - Initialize(); + // Initialize async, no need to wait for it + Task.Run(Initialize); } public DisplayConditionPredicate DisplayConditionPredicate => (DisplayConditionPredicate) Model; @@ -83,6 +86,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions set => SetAndNotify(ref _selectedRightSideProperty, value); } + public object RightStaticValue + { + get => _rightStaticValue; + set => SetAndNotify(ref _rightStaticValue, value); + } + public int RightSideTransitionIndex { get => _rightSideTransitionIndex; @@ -101,121 +110,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions set => SetAndNotify(ref _operators, value); } - public void Initialize() + public DisplayConditionOperator SelectedOperator { - Task.Run(() => - { - // Get the data models - LeftSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization(); - RightSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization(); - if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule())) - { - LeftSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule())); - RightSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule())); - } - - // Determine which types are currently supported - var editors = _dataModelVisualizationService.RegisteredDataModelEditors; - _supportedInputTypes = editors.Select(e => e.SupportedType).ToList(); - _supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes)); - - IsInitialized = true; - Update(); - }); + get => _selectedOperator; + set => SetAndNotify(ref _selectedOperator, value); } - public override void Update() - { - if (!IsInitialized) - return; - - // If static, only allow selecting properties also supported by input - if (DisplayConditionPredicate.PredicateType == PredicateType.Static) - LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray()); - - // Determine the left side property first - SelectedLeftSideProperty = DisplayConditionPredicate.LeftPropertyPath != null - ? LeftSideDataModel.GetChildByPath(DisplayConditionPredicate.LeftDataModelGuid, DisplayConditionPredicate.LeftPropertyPath) - : null; - var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType; - - // Get the supported operators - Operators = _dataModelService.GetCompatibleConditionOperators(leftSideType); - if (DisplayConditionPredicate.Operator == null || !DisplayConditionPredicate.Operator.SupportsType(leftSideType)) - DisplayConditionPredicate.Operator = Operators.FirstOrDefault(o => o.SupportsType(leftSideType)); - - if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic) - UpdateRightSideDynamic(leftSideType); - else - UpdateRightSideStatic(leftSideType); - - DisplayConditionPredicate.CreateExpression(_dataModelService); - NotifyOfPropertyChange(nameof(DisplayConditionPredicate)); - } - - #region Dynamic input - - private void UpdateRightSideDynamic(Type leftSideType) - { - // Right side may only select properties matching the left side - if (SelectedLeftSideProperty != null) - RightSideDataModel.ApplyTypeFilter(true, leftSideType); - else - RightSideDataModel.ApplyTypeFilter(true); - - // Determine the right side property - if (DisplayConditionPredicate.RightPropertyPath != null) - { - // Ensure the right side property still matches the left side type, else set it to null - var selectedProperty = RightSideDataModel.GetChildByPath(DisplayConditionPredicate.RightDataModelGuid, DisplayConditionPredicate.RightPropertyPath); - SelectedRightSideProperty = selectedProperty.IsMatchingFilteredTypes ? selectedProperty : null; - } - else - SelectedRightSideProperty = null; - } - - #endregion - - #region Static input - - private void UpdateRightSideStatic(Type leftSideType) - { - if (DisplayConditionPredicate.RightStaticValue != null && DisplayConditionPredicate.RightStaticValue.GetType() != leftSideType) - DisplayConditionPredicate.RightStaticValue = null; - } - - public void ActivateRightSideInputViewModel() - { - if (SelectedLeftSideProperty?.PropertyInfo == null) - return; - - RightSideTransitionIndex = 1; - RightSideInputViewModel = _dataModelVisualizationService.GetDataModelInputViewModel( - SelectedLeftSideProperty.PropertyInfo.PropertyType, - SelectedLeftSideProperty.PropertyDescription, - DisplayConditionPredicate.RightStaticValue, - UpdateInputValue - ); - _eventAggregator.Subscribe(this); - } - - public void UpdateInputValue(object value, bool isSubmitted) - { - if (isSubmitted) - { - var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType; - - if (value != null && value.GetType() != leftSideType) - DisplayConditionPredicate.RightStaticValue = Convert.ChangeType(value, leftSideType); - else - DisplayConditionPredicate.RightStaticValue = value; - Update(); - } - - RightSideTransitionIndex = 0; - RightSideInputViewModel = null; - _eventAggregator.Unsubscribe(this); - } + public DelegateCommand SelectLeftPropertyCommand { get; } + public DelegateCommand SelectRightPropertyCommand { get; } + public DelegateCommand SelectOperatorCommand { get; } public void Handle(MainWindowKeyEvent message) { @@ -237,32 +140,119 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions RightSideInputViewModel.Submit(); } - #endregion + public void Initialize() + { + // Get the data models + LeftSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization(); + RightSideDataModel = _dataModelVisualizationService.GetMainDataModelVisualization(); + if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule())) + { + LeftSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule())); + RightSideDataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule())); + } - #region Commands + // Determine which types are currently supported + var editors = _dataModelVisualizationService.RegisteredDataModelEditors; + _supportedInputTypes = editors.Select(e => e.SupportedType).ToList(); + _supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes)); - public DelegateCommand SelectLeftPropertyCommand { get; } - public DelegateCommand SelectRightPropertyCommand { get; } - public DelegateCommand SelectOperatorCommand { get; } + IsInitialized = true; + Update(); + } + + public override void Update() + { + if (!IsInitialized) + return; + + // If static, only allow selecting properties also supported by input + if (DisplayConditionPredicate.PredicateType == PredicateType.Static) + LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray()); + + // Determine the left side property first + SelectedLeftSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Left); + var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType; + + // Get the supported operators + Operators = _dataModelService.GetCompatibleConditionOperators(leftSideType); + if (DisplayConditionPredicate.Operator == null) + DisplayConditionPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); + SelectedOperator = DisplayConditionPredicate.Operator; + + // Determine the right side + if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic) + { + SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right); + RightSideDataModel.ApplyTypeFilter(true, leftSideType); + } + else + RightStaticValue = DisplayConditionPredicate.RightStaticValue; + } + + public void ApplyLeftSide() + { + DisplayConditionPredicate.UpdateLeftSide(SelectedLeftSideProperty.DataModel, SelectedLeftSideProperty.PropertyPath); + SelectedOperator = DisplayConditionPredicate.Operator; + Update(); + } + + public void ApplyRightSideDynamic() + { + DisplayConditionPredicate.UpdateRightSide(SelectedRightSideProperty.DataModel, SelectedRightSideProperty.PropertyPath); + Update(); + } + + public void ApplyRightSideStatic(object value, bool isSubmitted) + { + if (isSubmitted) + { + DisplayConditionPredicate.UpdateRightSide(value); + Update(); + } + + RightSideTransitionIndex = 0; + RightSideInputViewModel = null; + RightStaticValue = value; + _eventAggregator.Unsubscribe(this); + } + + public void ApplyOperator() + { + DisplayConditionPredicate.UpdateOperator(SelectedOperator); + Update(); + } + + public void ActivateRightSideInputViewModel() + { + if (SelectedLeftSideProperty?.PropertyInfo == null) + return; + + RightSideTransitionIndex = 1; + RightSideInputViewModel = _dataModelVisualizationService.GetDataModelInputViewModel( + SelectedLeftSideProperty.PropertyInfo.PropertyType, + SelectedLeftSideProperty.PropertyDescription, + DisplayConditionPredicate.RightStaticValue, + ApplyRightSideStatic + ); + _eventAggregator.Subscribe(this); + } private void ExecuteSelectLeftProperty(object context) { - if (!(context is DataModelVisualizationViewModel vm)) + if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel)) return; - DisplayConditionPredicate.LeftPropertyPath = vm.GetCurrentPath(); - DisplayConditionPredicate.LeftDataModelGuid = vm.DataModel.PluginInfo.Guid; - Update(); + SelectedLeftSideProperty = dataModelVisualizationViewModel; + ApplyLeftSide(); } private void ExecuteSelectRightProperty(object context) { - if (!(context is DataModelVisualizationViewModel vm)) + if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel)) return; - DisplayConditionPredicate.RightPropertyPath = vm.GetCurrentPath(); - DisplayConditionPredicate.RightDataModelGuid = vm.DataModel.PluginInfo.Guid; - Update(); + SelectedRightSideProperty = dataModelVisualizationViewModel; + ApplyRightSideDynamic(); } private void ExecuteSelectOperatorCommand(object context) @@ -270,10 +260,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions if (!(context is DisplayConditionOperator displayConditionOperator)) return; - DisplayConditionPredicate.Operator = displayConditionOperator; - Update(); + SelectedOperator = displayConditionOperator; + ApplyOperator(); } - - #endregion } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs index 70ac868fd..7f0586705 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs @@ -32,7 +32,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions // Ensure the layer has a root display condition group if (e.RenderProfileElement.DisplayConditionGroup == null) - e.RenderProfileElement.DisplayConditionGroup = new DisplayConditionGroup(); + e.RenderProfileElement.DisplayConditionGroup = new DisplayConditionGroup(null); RootGroup = _displayConditionsVmFactory.DisplayConditionGroupViewModel(e.RenderProfileElement.DisplayConditionGroup, null); RootGroup.IsRootGroup = true;