diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs index d21e96406..754fef6a3 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionList.cs @@ -17,9 +17,6 @@ namespace Artemis.Core.Models.Profile.Conditions { Parent = parent; Entity = new DisplayConditionListEntity(); - - // There is always a child root group, add it - AddChild(new DisplayConditionGroup(this)); } public DisplayConditionList(DisplayConditionPart parent, DisplayConditionListEntity entity) @@ -27,16 +24,6 @@ namespace Artemis.Core.Models.Profile.Conditions Parent = parent; Entity = entity; ListOperator = (ListOperator) entity.ListOperator; - - // There should only be one child and it should be a group - var rootGroup = Entity.Children.SingleOrDefault() as DisplayConditionGroupEntity; - if (rootGroup == null) - { - Entity.Children.Clear(); - AddChild(new DisplayConditionGroup(this)); - } - else - AddChild(new DisplayConditionGroup(this, rootGroup)); } public DisplayConditionListEntity Entity { get; set; } @@ -55,6 +42,8 @@ namespace Artemis.Core.Models.Profile.Conditions public override bool EvaluateObject(object target) { + if (!Children.Any()) + return false; if (!(target is IList list)) return false; @@ -92,17 +81,28 @@ namespace Artemis.Core.Models.Profile.Conditions internal override void Initialize(IDataModelService dataModelService) { - // Target list - if (Entity.ListDataModelGuid != null) - { - var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.ListDataModelGuid.Value); - if (dataModel != null && dataModel.ContainsPath(Entity.ListPropertyPath)) - UpdateList(dataModel, Entity.ListPropertyPath); - } + if (Entity.ListDataModelGuid == null) + return; - // Children - var rootGroup = (DisplayConditionGroup) Children.Single(); - rootGroup.Initialize(dataModelService); + // Get the data model and ensure the path is valid + var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.ListDataModelGuid.Value); + if (dataModel == null || !dataModel.ContainsPath(Entity.ListPropertyPath)) + return; + + // Populate properties and create the accessor expression + ListDataModel = dataModel; + ListPropertyPath = Entity.ListPropertyPath; + CreateExpression(); + + // There should only be one child and it should be a group + if (Entity.Children.SingleOrDefault() is DisplayConditionGroupEntity rootGroup) + AddChild(new DisplayConditionGroup(this, rootGroup)); + else + { + Entity.Children.Clear(); + AddChild(new DisplayConditionGroup(this)); + } + Children[0].Initialize(dataModelService); } public void UpdateList(DataModel dataModel, string path) @@ -120,19 +120,30 @@ namespace Artemis.Core.Models.Profile.Conditions throw new ArtemisCoreException($"The path '{path}' does not contain a list"); } + // Remove the old root group that was tied to the old data model + while (Children.Any()) + RemoveChild(Children[0]); + ListDataModel = dataModel; ListPropertyPath = path; - if (dataModel != null) - { - var parameter = Expression.Parameter(typeof(object), "listDataModel"); - var accessor = path.Split('.').Aggregate( - Expression.Convert(parameter, dataModel.GetType()), - (expression, s) => Expression.Convert(Expression.Property(expression, s), typeof(IList))); + if (dataModel == null) + return; - var lambda = Expression.Lambda>(accessor, parameter); - CompiledListAccessor = lambda.Compile(); - } + // Create a new root group + AddChild(new DisplayConditionGroup(this)); + CreateExpression(); + } + + public void CreateExpression() + { + var parameter = Expression.Parameter(typeof(object), "listDataModel"); + var accessor = ListPropertyPath.Split('.').Aggregate( + Expression.Convert(parameter, ListDataModel.GetType()), + (expression, s) => Expression.Convert(Expression.Property(expression, s), typeof(IList))); + + var lambda = Expression.Lambda>(accessor, parameter); + CompiledListAccessor = lambda.Compile(); } public Func CompiledListAccessor { get; set; } diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs index 76ae54239..a4266ef37 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionListPredicate.cs @@ -19,6 +19,8 @@ namespace Artemis.Core.Models.Profile.Conditions Parent = parent; PredicateType = predicateType; Entity = new DisplayConditionListPredicateEntity(); + + ApplyParentList(); } public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity) @@ -26,6 +28,8 @@ namespace Artemis.Core.Models.Profile.Conditions Parent = parent; Entity = entity; PredicateType = (PredicateType) entity.PredicateType; + + ApplyParentList(); } public DisplayConditionListPredicateEntity Entity { get; set; } @@ -43,6 +47,20 @@ namespace Artemis.Core.Models.Profile.Conditions public Func CompiledListPredicate { get; private set; } + public void ApplyParentList() + { + var current = Parent; + while (current != null) + { + if (current is DisplayConditionList parentList) + { + UpdateList(parentList.ListDataModel, parentList.ListPropertyPath); + return; + } + current = current.Parent; + } + } + public void UpdateList(DataModel dataModel, string path) { if (dataModel != null && path == null) @@ -66,9 +84,9 @@ namespace Artemis.Core.Models.Profile.Conditions ListDataModel = dataModel; ListPropertyPath = path; - if (!ListContainsInnerPath(LeftPropertyPath)) + if (LeftPropertyPath != null && !ListContainsInnerPath(LeftPropertyPath)) LeftPropertyPath = null; - if (!ListContainsInnerPath(RightPropertyPath)) + if (RightPropertyPath != null && !ListContainsInnerPath(RightPropertyPath)) RightPropertyPath = null; CreateExpression(); diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs index a766b91d7..016ae6298 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelListPropertiesViewModel.cs @@ -34,9 +34,9 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared set => SetAndNotify(ref _displayValue, value); } - public override string PropertyPath => Parent?.PropertyPath; + public override string PropertyPath => null; - public override string DisplayPropertyPath => Parent?.DisplayPropertyPath; + public override string DisplayPropertyPath => null; public override void Update(IDataModelVisualizationService dataModelVisualizationService) { diff --git a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs index c3ef78f8d..223f3b110 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/Shared/DataModelVisualizationViewModel.cs @@ -198,6 +198,9 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared public DataModelVisualizationViewModel GetChildByPath(Guid dataModelGuid, string propertyPath) { + if (propertyPath == null) + return null; + // Ensure children are populated by requesting an update if (!IsVisualizationExpanded) { diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index bdb8a2fc3..e4f0c7b4b 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -77,9 +77,10 @@ namespace Artemis.UI.Ninject.Factories } public interface IDisplayConditionsVmFactory : IVmFactory { - DisplayConditionGroupViewModel DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent); + DisplayConditionGroupViewModel DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, bool isListGroup); DisplayConditionListViewModel DisplayConditionListViewModel(DisplayConditionList displayConditionList, DisplayConditionViewModel parent); DisplayConditionPredicateViewModel DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent); + DisplayConditionListPredicateViewModel DisplayConditionListPredicateViewModel(DisplayConditionListPredicate displayConditionListPredicate, DisplayConditionViewModel parent); } public interface ILayerPropertyVmFactory : IVmFactory diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Abstract/DisplayConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Abstract/DisplayConditionViewModel.cs index 69728ff3a..68fd864be 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Abstract/DisplayConditionViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/Abstract/DisplayConditionViewModel.cs @@ -1,6 +1,5 @@ using System; using Artemis.Core.Models.Profile.Conditions.Abstract; -using Artemis.UI.Shared.DataModelVisualization.Shared; using Stylet; namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract @@ -29,11 +28,6 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract public abstract void Update(); - public virtual DataModelPropertiesViewModel GetDataModelOverride() - { - return Parent?.GetDataModelOverride(); - } - public virtual void Delete() { Model.Parent.RemoveChild(Model); diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupView.xaml index cd31bb539..b0e217763 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupView.xaml @@ -1,4 +1,4 @@ - + d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type local:DisplayConditionGroupViewModel}}"> + @@ -68,23 +72,23 @@ - + + + + CommandParameter="List" + IsEnabled="{Binding Data.IsListGroup, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}"> @@ -116,6 +121,7 @@ + diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs index c5bd75612..279149129 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionGroupViewModel.cs @@ -18,9 +18,10 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions private bool _isInitialized; private bool _isRootGroup; - public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, + public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, bool isListGroup, IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory) : base(displayConditionGroup, parent) { + IsListGroup = isListGroup; _profileEditorService = profileEditorService; _displayConditionsVmFactory = displayConditionsVmFactory; @@ -33,6 +34,8 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions }); } + public bool IsListGroup { get; } + public DisplayConditionGroup DisplayConditionGroup => (DisplayConditionGroup) Model; public bool IsRootGroup @@ -62,15 +65,27 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions var enumValue = Enum.Parse(type); DisplayConditionGroup.BooleanOperator = enumValue; NotifyOfPropertyChange(nameof(SelectedBooleanOperator)); + + _profileEditorService.UpdateSelectedProfileElement(); } public void AddCondition(string type) { if (type == "Static") - DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static)); + { + if (!IsListGroup) + DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static)); + else + DisplayConditionGroup.AddChild(new DisplayConditionListPredicate(DisplayConditionGroup, PredicateType.Static)); + } else if (type == "Dynamic") - DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic)); - else if (type == "List") + { + if (!IsListGroup) + DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic)); + else + DisplayConditionGroup.AddChild(new DisplayConditionListPredicate(DisplayConditionGroup, PredicateType.Dynamic)); + } + else if (type == "List" && !IsListGroup) DisplayConditionGroup.AddChild(new DisplayConditionList(DisplayConditionGroup)); Update(); @@ -106,13 +121,18 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions switch (childModel) { case DisplayConditionGroup displayConditionGroup: - Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this)); + Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this, IsListGroup)); break; case DisplayConditionList displayConditionListPredicate: Children.Add(_displayConditionsVmFactory.DisplayConditionListViewModel(displayConditionListPredicate, this)); break; case DisplayConditionPredicate displayConditionPredicate: - Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this)); + if (!IsListGroup) + Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this)); + break; + case DisplayConditionListPredicate displayConditionListPredicate: + if (IsListGroup) + Children.Add(_displayConditionsVmFactory.DisplayConditionListPredicateViewModel(displayConditionListPredicate, this)); break; } } diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml new file mode 100644 index 000000000..5702485f0 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml.cs new file mode 100644 index 000000000..396bd3f41 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateView.xaml.cs @@ -0,0 +1,26 @@ +using System.Windows; +using System.Windows.Controls; + +namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions +{ + /// + /// Interaction logic for DisplayConditionListPredicateView.xaml + /// + public partial class DisplayConditionListPredicateView : UserControl + { + public DisplayConditionListPredicateView() + { + InitializeComponent(); + } + + private void PropertyButton_OnClick(object sender, RoutedEventArgs e) + { + // DataContext is not set when using left button, I don't know why but there it is + if (sender is Button button && button.ContextMenu != null) + { + button.ContextMenu.DataContext = button.DataContext; + button.ContextMenu.IsOpen = true; + } + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs new file mode 100644 index 000000000..686aa9642 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListPredicateViewModel.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Timers; +using System.Windows; +using System.Windows.Input; +using Artemis.Core.Models.Profile.Conditions; +using Artemis.Core.Plugins.Models; +using Artemis.Core.Services; +using Artemis.Core.Services.Interfaces; +using Artemis.UI.Events; +using Artemis.UI.Exceptions; +using Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract; +using Artemis.UI.Shared.DataModelVisualization; +using Artemis.UI.Shared.DataModelVisualization.Shared; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Services.Interfaces; +using Artemis.UI.Utilities; +using Stylet; + +namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions +{ + public class DisplayConditionListPredicateViewModel : DisplayConditionViewModel, IHandle, IHandle + { + private readonly IDataModelService _dataModelService; + private readonly IDataModelVisualizationService _dataModelVisualizationService; + private readonly IEventAggregator _eventAggregator; + private readonly IProfileEditorService _profileEditorService; + private readonly Timer _updateTimer; + private bool _isInitialized; + private DataModelVisualizationViewModel _leftSideDataModel; + private BindableCollection _operators; + private DataModelVisualizationViewModel _rightSideDataModel; + private DataModelInputViewModel _rightSideInputViewModel; + private int _rightSideTransitionIndex; + private object _rightStaticValue; + private DataModelVisualizationViewModel _selectedLeftSideProperty; + private DisplayConditionOperator _selectedOperator; + private DataModelVisualizationViewModel _selectedRightSideProperty; + + private List _supportedInputTypes; + + public DisplayConditionListPredicateViewModel( + DisplayConditionListPredicate displayConditionListPredicate, + DisplayConditionViewModel parent, + IProfileEditorService profileEditorService, + IDataModelVisualizationService dataModelVisualizationService, + IDataModelService dataModelService, + ISettingsService settingsService, + IEventAggregator eventAggregator) : base(displayConditionListPredicate, parent) + { + _profileEditorService = profileEditorService; + _dataModelVisualizationService = dataModelVisualizationService; + _dataModelService = dataModelService; + _eventAggregator = eventAggregator; + _updateTimer = new Timer(500); + _supportedInputTypes = new List(); + + SelectLeftPropertyCommand = new DelegateCommand(ExecuteSelectLeftProperty); + SelectRightPropertyCommand = new DelegateCommand(ExecuteSelectRightProperty); + SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand); + Operators = new BindableCollection(); + + ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues"); + + // Initialize async, no need to wait for it + Task.Run(Initialize); + } + + public DisplayConditionListPredicate DisplayConditionListPredicate => (DisplayConditionListPredicate) Model; + public bool ShowRightSidePropertySelection => DisplayConditionListPredicate.PredicateType == PredicateType.Dynamic; + public bool CanActivateRightSideInputViewModel => SelectedLeftSideProperty?.PropertyInfo != null; + public PluginSetting ShowDataModelValues { get; } + + public bool IsInitialized + { + get => _isInitialized; + private set => SetAndNotify(ref _isInitialized, value); + } + + public bool LeftSideDataModelOpen { get; set; } + + public DataModelVisualizationViewModel LeftSideDataModel + { + get => _leftSideDataModel; + set => SetAndNotify(ref _leftSideDataModel, value); + } + + public DataModelVisualizationViewModel RightSideDataModel + { + get => _rightSideDataModel; + set => SetAndNotify(ref _rightSideDataModel, value); + } + + public bool RightSideDataModelOpen { get; set; } + + public DataModelVisualizationViewModel SelectedLeftSideProperty + { + get => _selectedLeftSideProperty; + set + { + if (!SetAndNotify(ref _selectedLeftSideProperty, value)) return; + NotifyOfPropertyChange(nameof(CanActivateRightSideInputViewModel)); + } + } + + public DataModelVisualizationViewModel SelectedRightSideProperty + { + get => _selectedRightSideProperty; + set => SetAndNotify(ref _selectedRightSideProperty, value); + } + + public object RightStaticValue + { + get => _rightStaticValue; + set => SetAndNotify(ref _rightStaticValue, value); + } + + public int RightSideTransitionIndex + { + get => _rightSideTransitionIndex; + set => SetAndNotify(ref _rightSideTransitionIndex, value); + } + + public DataModelInputViewModel RightSideInputViewModel + { + get => _rightSideInputViewModel; + set => SetAndNotify(ref _rightSideInputViewModel, value); + } + + public BindableCollection Operators + { + get => _operators; + set => SetAndNotify(ref _operators, value); + } + + public DisplayConditionOperator SelectedOperator + { + get => _selectedOperator; + set => SetAndNotify(ref _selectedOperator, value); + } + + public DelegateCommand SelectLeftPropertyCommand { get; } + public DelegateCommand SelectRightPropertyCommand { get; } + public DelegateCommand SelectOperatorCommand { get; } + + public void Handle(MainWindowKeyEvent message) + { + if (RightSideInputViewModel == null) + return; + + if (!message.KeyDown && message.EventArgs.Key == Key.Escape) + RightSideInputViewModel.Cancel(); + if (!message.KeyDown && message.EventArgs.Key == Key.Enter) + RightSideInputViewModel.Submit(); + } + + public void Handle(MainWindowMouseEvent message) + { + if (RightSideInputViewModel == null) + return; + + if (message.Sender is FrameworkElement frameworkElement && !frameworkElement.IsDescendantOf(RightSideInputViewModel.View)) + RightSideInputViewModel.Submit(); + } + + public override void Delete() + { + base.Delete(); + _profileEditorService.UpdateSelectedProfileElement(); + } + + public void Initialize() + { + // Get the data models + LeftSideDataModel = GetListDataModel(); + RightSideDataModel = GetListDataModel(); + LeftSideDataModel.UpdateRequested += LeftDataModelUpdateRequested; + RightSideDataModel.UpdateRequested += RightDataModelUpdateRequested; + + // 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)); + + Update(); + + _updateTimer.Start(); + _updateTimer.Elapsed += OnUpdateTimerOnElapsed; + + IsInitialized = true; + } + + public override void Update() + { + // Not yet initialized if these are null + if (LeftSideDataModel == null || RightSideDataModel == null) + return; + + var listDataModelGuid = DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid; + + // If static, only allow selecting properties also supported by input + if (DisplayConditionListPredicate.PredicateType == PredicateType.Static) + LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray()); + + // Determine the left side property first + SelectedLeftSideProperty = LeftSideDataModel.GetChildByPath(listDataModelGuid, DisplayConditionListPredicate.LeftPropertyPath); + var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType; + + // Get the supported operators + Operators.Clear(); + Operators.AddRange(_dataModelService.GetCompatibleConditionOperators(leftSideType)); + if (DisplayConditionListPredicate.Operator == null) + DisplayConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType))); + SelectedOperator = DisplayConditionListPredicate.Operator; + + // Determine the right side + if (DisplayConditionListPredicate.PredicateType == PredicateType.Dynamic) + { + SelectedRightSideProperty = RightSideDataModel.GetChildByPath(listDataModelGuid, DisplayConditionListPredicate.RightPropertyPath); + RightSideDataModel.ApplyTypeFilter(true, leftSideType); + } + else + RightStaticValue = DisplayConditionListPredicate.RightStaticValue; + } + + public void ApplyLeftSide() + { + DisplayConditionListPredicate.UpdateLeftSide(SelectedLeftSideProperty.PropertyPath); + _profileEditorService.UpdateSelectedProfileElement(); + + SelectedOperator = DisplayConditionListPredicate.Operator; + Update(); + } + + public void ApplyRightSideDynamic() + { + DisplayConditionListPredicate.UpdateRightSideDynamic(SelectedRightSideProperty.PropertyPath); + _profileEditorService.UpdateSelectedProfileElement(); + + Update(); + } + + public void ApplyRightSideStatic(object value, bool isSubmitted) + { + if (isSubmitted) + { + DisplayConditionListPredicate.UpdateRightSideStatic(value); + _profileEditorService.UpdateSelectedProfileElement(); + + Update(); + } + + RightSideTransitionIndex = 0; + RightSideInputViewModel = null; + RightStaticValue = value; + _eventAggregator.Unsubscribe(this); + } + + public void ApplyOperator() + { + DisplayConditionListPredicate.UpdateOperator(SelectedOperator); + _profileEditorService.UpdateSelectedProfileElement(); + + Update(); + } + + public void ActivateRightSideInputViewModel() + { + if (SelectedLeftSideProperty?.PropertyInfo == null) + return; + + RightSideTransitionIndex = 1; + RightSideInputViewModel = _dataModelVisualizationService.GetDataModelInputViewModel( + SelectedLeftSideProperty.PropertyInfo.PropertyType, + SelectedLeftSideProperty.PropertyDescription, + DisplayConditionListPredicate.RightStaticValue, + ApplyRightSideStatic + ); + _eventAggregator.Subscribe(this); + } + + protected override void Dispose(bool disposing) + { + _updateTimer.Stop(); + _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; + } + + private void OnUpdateTimerOnElapsed(object sender, ElapsedEventArgs e) + { + if (LeftSideDataModelOpen) + LeftSideDataModel.Update(_dataModelVisualizationService); + else if (RightSideDataModelOpen) + RightSideDataModel.Update(_dataModelVisualizationService); + } + + private void RightDataModelUpdateRequested(object sender, EventArgs e) + { + var listDataModelGuid = DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid; + var leftSideType = SelectedLeftSideProperty?.PropertyInfo?.PropertyType; + + // If the right side property is missing it may be available now that the data model has been updated + if (SelectedRightSideProperty == null && DisplayConditionListPredicate.RightPropertyPath != null) + SelectedRightSideProperty = RightSideDataModel.GetChildByPath(listDataModelGuid, DisplayConditionListPredicate.RightPropertyPath); + + // With the data model updated, also reapply the filter + RightSideDataModel.ApplyTypeFilter(true, leftSideType); + } + + private void LeftDataModelUpdateRequested(object sender, EventArgs e) + { + if (DisplayConditionListPredicate.PredicateType == PredicateType.Static) + LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray()); + } + + private DataModelVisualizationViewModel GetListDataModel() + { + if (DisplayConditionListPredicate.ListDataModel == null || DisplayConditionListPredicate.ListPropertyPath == null) + throw new ArtemisUIException("Cannot create a list predicate without first selecting a target list"); + + var dataModel = _dataModelVisualizationService.GetMainDataModelVisualization(); + if (!_dataModelVisualizationService.GetPluginExtendsDataModel(_profileEditorService.GetCurrentModule())) + dataModel.Children.Add(_dataModelVisualizationService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule())); + + var listDataModel = (DataModelListViewModel) dataModel.GetChildByPath( + DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid, + DisplayConditionListPredicate.ListPropertyPath + ); + + return listDataModel.GetListTypeViewModel(_dataModelVisualizationService); + } + + private void ExecuteSelectLeftProperty(object context) + { + if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel)) + return; + + SelectedLeftSideProperty = dataModelVisualizationViewModel; + ApplyLeftSide(); + } + + private void ExecuteSelectRightProperty(object context) + { + if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel)) + return; + + SelectedRightSideProperty = dataModelVisualizationViewModel; + ApplyRightSideDynamic(); + } + + private void ExecuteSelectOperatorCommand(object context) + { + if (!(context is DisplayConditionOperator displayConditionOperator)) + return; + + SelectedOperator = displayConditionOperator; + ApplyOperator(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListView.xaml index 58ccf5c2c..b426f0512 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionListView.xaml @@ -30,7 +30,7 @@ - + @@ -55,11 +55,12 @@