mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Display conditions - Seperate list conditions into their own type
This commit is contained in:
parent
f2f77da953
commit
f359256ede
@ -12,19 +12,21 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
public DisplayConditionGroup(DisplayConditionPart parent)
|
public DisplayConditionGroup(DisplayConditionPart parent)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DisplayConditionGroupEntity = new DisplayConditionGroupEntity();
|
Entity = new DisplayConditionGroupEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionGroup(DisplayConditionPart parent, DisplayConditionGroupEntity entity)
|
public DisplayConditionGroup(DisplayConditionPart parent, DisplayConditionGroupEntity entity)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DisplayConditionGroupEntity = entity;
|
Entity = entity;
|
||||||
BooleanOperator = (BooleanOperator) DisplayConditionGroupEntity.BooleanOperator;
|
BooleanOperator = (BooleanOperator) Entity.BooleanOperator;
|
||||||
|
|
||||||
foreach (var childEntity in DisplayConditionGroupEntity.Children)
|
foreach (var childEntity in Entity.Children)
|
||||||
{
|
{
|
||||||
if (childEntity is DisplayConditionGroupEntity groupEntity)
|
if (childEntity is DisplayConditionGroupEntity groupEntity)
|
||||||
AddChild(new DisplayConditionGroup(this, groupEntity));
|
AddChild(new DisplayConditionGroup(this, groupEntity));
|
||||||
|
else if (childEntity is DisplayConditionListEntity listEntity)
|
||||||
|
AddChild(new DisplayConditionList(this, listEntity));
|
||||||
else if (childEntity is DisplayConditionPredicateEntity predicateEntity)
|
else if (childEntity is DisplayConditionPredicateEntity predicateEntity)
|
||||||
AddChild(new DisplayConditionPredicate(this, predicateEntity));
|
AddChild(new DisplayConditionPredicate(this, predicateEntity));
|
||||||
else if (childEntity is DisplayConditionListPredicateEntity listPredicateEntity)
|
else if (childEntity is DisplayConditionListPredicateEntity listPredicateEntity)
|
||||||
@ -33,7 +35,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BooleanOperator BooleanOperator { get; set; }
|
public BooleanOperator BooleanOperator { get; set; }
|
||||||
public DisplayConditionGroupEntity DisplayConditionGroupEntity { get; set; }
|
public DisplayConditionGroupEntity Entity { get; set; }
|
||||||
|
|
||||||
public override bool Evaluate()
|
public override bool Evaluate()
|
||||||
{
|
{
|
||||||
@ -80,10 +82,10 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator;
|
Entity.BooleanOperator = (int) BooleanOperator;
|
||||||
|
|
||||||
DisplayConditionGroupEntity.Children.Clear();
|
Entity.Children.Clear();
|
||||||
DisplayConditionGroupEntity.Children.AddRange(Children.Select(c => c.GetEntity()));
|
Entity.Children.AddRange(Children.Select(c => c.GetEntity()));
|
||||||
foreach (var child in Children)
|
foreach (var child in Children)
|
||||||
child.ApplyToEntity();
|
child.ApplyToEntity();
|
||||||
}
|
}
|
||||||
@ -96,7 +98,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
internal override DisplayConditionPartEntity GetEntity()
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
{
|
{
|
||||||
return DisplayConditionGroupEntity;
|
return Entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Artemis.Core.Exceptions;
|
||||||
|
using Artemis.Core.Models.Profile.Conditions.Abstract;
|
||||||
|
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||||
|
using Artemis.Core.Services.Interfaces;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Models.Profile.Conditions
|
||||||
|
{
|
||||||
|
public class DisplayConditionList : DisplayConditionPart
|
||||||
|
{
|
||||||
|
public DisplayConditionList(DisplayConditionPart parent)
|
||||||
|
{
|
||||||
|
Parent = parent;
|
||||||
|
Entity = new DisplayConditionListEntity();
|
||||||
|
|
||||||
|
// There is always a child root group, add it
|
||||||
|
AddChild(new DisplayConditionGroup(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConditionList(DisplayConditionPart parent, DisplayConditionListEntity entity)
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
|
||||||
|
public ListOperator ListOperator { get; set; }
|
||||||
|
public DataModel ListDataModel { get; private set; }
|
||||||
|
public string ListPropertyPath { get; private set; }
|
||||||
|
|
||||||
|
public override bool Evaluate()
|
||||||
|
{
|
||||||
|
if (CompiledListAccessor == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return EvaluateObject(CompiledListAccessor(ListDataModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool EvaluateObject(object target)
|
||||||
|
{
|
||||||
|
if (!(target is IList list))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var objectList = list.Cast<object>();
|
||||||
|
return ListOperator switch
|
||||||
|
{
|
||||||
|
ListOperator.Any => objectList.Any(o => Children[0].EvaluateObject(o)),
|
||||||
|
ListOperator.All => objectList.All(o => Children[0].EvaluateObject(o)),
|
||||||
|
ListOperator.None => objectList.Any(o => !Children[0].EvaluateObject(o)),
|
||||||
|
ListOperator.Count => false,
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void ApplyToEntity()
|
||||||
|
{
|
||||||
|
// Target list
|
||||||
|
Entity.ListDataModelGuid = ListDataModel?.PluginInfo?.Guid;
|
||||||
|
Entity.ListPropertyPath = ListPropertyPath;
|
||||||
|
|
||||||
|
// Operator
|
||||||
|
Entity.ListOperator = (int) ListOperator;
|
||||||
|
|
||||||
|
// Children
|
||||||
|
Entity.Children.Clear();
|
||||||
|
Entity.Children.AddRange(Children.Select(c => c.GetEntity()));
|
||||||
|
foreach (var child in Children)
|
||||||
|
child.ApplyToEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
|
{
|
||||||
|
return Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Children
|
||||||
|
var rootGroup = (DisplayConditionGroup) Children.Single();
|
||||||
|
rootGroup.Initialize(dataModelService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateList(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");
|
||||||
|
|
||||||
|
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}'");
|
||||||
|
if (dataModel.GetListTypeAtPath(path) == null)
|
||||||
|
throw new ArtemisCoreException($"The path '{path}' does not contain a list");
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDataModel = dataModel;
|
||||||
|
ListPropertyPath = path;
|
||||||
|
|
||||||
|
if (dataModel != null)
|
||||||
|
{
|
||||||
|
var parameter = Expression.Parameter(typeof(object), "listDataModel");
|
||||||
|
var accessor = path.Split('.').Aggregate<string, Expression>(
|
||||||
|
Expression.Convert(parameter, dataModel.GetType()),
|
||||||
|
(expression, s) => Expression.Convert(Expression.Property(expression, s), typeof(IList)));
|
||||||
|
|
||||||
|
var lambda = Expression.Lambda<Func<object, IList>>(accessor, parameter);
|
||||||
|
CompiledListAccessor = lambda.Compile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<object, IList> CompiledListAccessor { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ListOperator
|
||||||
|
{
|
||||||
|
Any,
|
||||||
|
All,
|
||||||
|
None,
|
||||||
|
Count
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,106 +1,47 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using Artemis.Core.Exceptions;
|
using Artemis.Core.Exceptions;
|
||||||
|
using Artemis.Core.Extensions;
|
||||||
using Artemis.Core.Models.Profile.Conditions.Abstract;
|
using Artemis.Core.Models.Profile.Conditions.Abstract;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Artemis.Core.Models.Profile.Conditions
|
namespace Artemis.Core.Models.Profile.Conditions
|
||||||
{
|
{
|
||||||
public class DisplayConditionListPredicate : DisplayConditionPart
|
public class DisplayConditionListPredicate : DisplayConditionPart
|
||||||
{
|
{
|
||||||
public DisplayConditionListPredicate(DisplayConditionPart parent)
|
public DisplayConditionListPredicate(DisplayConditionPart parent, PredicateType predicateType)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DisplayConditionListPredicateEntity = new DisplayConditionListPredicateEntity();
|
PredicateType = predicateType;
|
||||||
|
Entity = new DisplayConditionListPredicateEntity();
|
||||||
// There is always a child root group, add it
|
|
||||||
AddChild(new DisplayConditionGroup(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity)
|
public DisplayConditionListPredicate(DisplayConditionPart parent, DisplayConditionListPredicateEntity entity)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DisplayConditionListPredicateEntity = entity;
|
Entity = entity;
|
||||||
ListOperator = (ListOperator) entity.ListOperator;
|
PredicateType = (PredicateType) entity.PredicateType;
|
||||||
|
|
||||||
// There should only be one child and it should be a group
|
|
||||||
var rootGroup = DisplayConditionListPredicateEntity.Children.SingleOrDefault() as DisplayConditionGroupEntity;
|
|
||||||
if (rootGroup == null)
|
|
||||||
{
|
|
||||||
DisplayConditionListPredicateEntity.Children.Clear();
|
|
||||||
AddChild(new DisplayConditionGroup(this));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
AddChild(new DisplayConditionGroup(this, rootGroup));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionListPredicateEntity DisplayConditionListPredicateEntity { get; set; }
|
public DisplayConditionListPredicateEntity Entity { get; set; }
|
||||||
|
|
||||||
public ListOperator ListOperator { get; set; }
|
public PredicateType PredicateType { get; set; }
|
||||||
|
public DisplayConditionOperator Operator { get; private set; }
|
||||||
|
|
||||||
|
public Type ListType { get; private set; }
|
||||||
public DataModel ListDataModel { get; private set; }
|
public DataModel ListDataModel { get; private set; }
|
||||||
public string ListPropertyPath { get; private set; }
|
public string ListPropertyPath { get; private set; }
|
||||||
|
|
||||||
public override bool Evaluate()
|
public string LeftPropertyPath { get; private set; }
|
||||||
{
|
public string RightPropertyPath { get; private set; }
|
||||||
return EvaluateObject(CompiledListAccessor(ListDataModel));
|
public object RightStaticValue { get; private set; }
|
||||||
}
|
|
||||||
|
|
||||||
public override bool EvaluateObject(object target)
|
public Func<object, bool> CompiledListPredicate { get; private set; }
|
||||||
{
|
|
||||||
if (!(target is IList list))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var objectList = list.Cast<object>();
|
|
||||||
return ListOperator switch
|
|
||||||
{
|
|
||||||
ListOperator.Any => objectList.Any(o => Children[0].EvaluateObject(o)),
|
|
||||||
ListOperator.All => objectList.All(o => Children[0].EvaluateObject(o)),
|
|
||||||
ListOperator.None => objectList.Any(o => !Children[0].EvaluateObject(o)),
|
|
||||||
ListOperator.Count => false,
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
|
||||||
{
|
|
||||||
// Target list
|
|
||||||
DisplayConditionListPredicateEntity.ListDataModelGuid = ListDataModel?.PluginInfo?.Guid;
|
|
||||||
DisplayConditionListPredicateEntity.ListPropertyPath = ListPropertyPath;
|
|
||||||
|
|
||||||
// Operator
|
|
||||||
DisplayConditionListPredicateEntity.ListOperator = (int) ListOperator;
|
|
||||||
|
|
||||||
// Children
|
|
||||||
DisplayConditionListPredicateEntity.Children.Clear();
|
|
||||||
DisplayConditionListPredicateEntity.Children.AddRange(Children.Select(c => c.GetEntity()));
|
|
||||||
foreach (var child in Children)
|
|
||||||
child.ApplyToEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override DisplayConditionPartEntity GetEntity()
|
|
||||||
{
|
|
||||||
return DisplayConditionListPredicateEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Initialize(IDataModelService dataModelService)
|
|
||||||
{
|
|
||||||
// Target list
|
|
||||||
if (DisplayConditionListPredicateEntity.ListDataModelGuid != null)
|
|
||||||
{
|
|
||||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionListPredicateEntity.ListDataModelGuid.Value);
|
|
||||||
if (dataModel != null && dataModel.ContainsPath(DisplayConditionListPredicateEntity.ListPropertyPath))
|
|
||||||
UpdateList(dataModel, DisplayConditionListPredicateEntity.ListPropertyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Children
|
|
||||||
var rootGroup = (DisplayConditionGroup) Children.Single();
|
|
||||||
rootGroup.Initialize(dataModelService);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateList(DataModel dataModel, string path)
|
public void UpdateList(DataModel dataModel, string path)
|
||||||
{
|
{
|
||||||
@ -111,35 +52,322 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
if (dataModel != null)
|
if (dataModel != null)
|
||||||
{
|
{
|
||||||
if (!dataModel.ContainsPath(path))
|
var listType = dataModel.GetListTypeAtPath(path);
|
||||||
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{path}'");
|
if (listType == null)
|
||||||
if (dataModel.GetListTypeAtPath(path) == null)
|
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a list at path '{path}'");
|
||||||
throw new ArtemisCoreException($"The path '{path}' does not contain a list");
|
|
||||||
|
ListType = listType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ListType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListDataModel = dataModel;
|
ListDataModel = dataModel;
|
||||||
ListPropertyPath = path;
|
ListPropertyPath = path;
|
||||||
|
|
||||||
if (dataModel != null)
|
if (!ListContainsInnerPath(LeftPropertyPath))
|
||||||
|
LeftPropertyPath = null;
|
||||||
|
if (!ListContainsInnerPath(RightPropertyPath))
|
||||||
|
RightPropertyPath = null;
|
||||||
|
|
||||||
|
CreateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateLeftSide(string path)
|
||||||
{
|
{
|
||||||
var parameter = Expression.Parameter(typeof(object), "listDataModel");
|
if (!ListContainsInnerPath(path))
|
||||||
var accessor = path.Split('.').Aggregate<string, Expression>(
|
throw new ArtemisCoreException($"List type {ListType.Name} does not contain path {path}");
|
||||||
Expression.Convert(parameter, dataModel.GetType()),
|
|
||||||
(expression, s) => Expression.Convert(Expression.Property(expression, s), typeof(IList)));
|
|
||||||
|
|
||||||
var lambda = Expression.Lambda<Func<object, IList>>(accessor, parameter);
|
LeftPropertyPath = path;
|
||||||
CompiledListAccessor = lambda.Compile();
|
|
||||||
}
|
ValidateOperator();
|
||||||
|
ValidateRightSide();
|
||||||
|
CreateExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<object, IList> CompiledListAccessor { get; set; }
|
public void UpdateRightSideDynamic(string path)
|
||||||
}
|
|
||||||
|
|
||||||
public enum ListOperator
|
|
||||||
{
|
{
|
||||||
Any,
|
if (!ListContainsInnerPath(path))
|
||||||
All,
|
throw new ArtemisCoreException($"List type {ListType.Name} does not contain path {path}");
|
||||||
None,
|
|
||||||
Count
|
PredicateType = PredicateType.Dynamic;
|
||||||
|
RightPropertyPath = path;
|
||||||
|
|
||||||
|
CreateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateRightSideStatic(object staticValue)
|
||||||
|
{
|
||||||
|
PredicateType = PredicateType.Static;
|
||||||
|
RightPropertyPath = null;
|
||||||
|
|
||||||
|
SetStaticValue(staticValue);
|
||||||
|
CreateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOperator(DisplayConditionOperator displayConditionOperator)
|
||||||
|
{
|
||||||
|
if (displayConditionOperator == null)
|
||||||
|
{
|
||||||
|
Operator = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LeftPropertyPath == null)
|
||||||
|
{
|
||||||
|
Operator = displayConditionOperator;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftType = GetTypeAtInnerPath(LeftPropertyPath);
|
||||||
|
if (displayConditionOperator.SupportsType(leftType))
|
||||||
|
Operator = displayConditionOperator;
|
||||||
|
|
||||||
|
CreateExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateExpression()
|
||||||
|
{
|
||||||
|
CompiledListPredicate = null;
|
||||||
|
|
||||||
|
if (Operator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the operator does not support a right side, create a static expression because the right side will simply be null
|
||||||
|
if (PredicateType == PredicateType.Dynamic && Operator.SupportsRightSide)
|
||||||
|
CreateDynamicExpression();
|
||||||
|
|
||||||
|
CreateStaticExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void ApplyToEntity()
|
||||||
|
{
|
||||||
|
Entity.PredicateType = (int) PredicateType;
|
||||||
|
Entity.ListDataModelGuid = ListDataModel?.PluginInfo?.Guid;
|
||||||
|
Entity.ListPropertyPath = ListPropertyPath;
|
||||||
|
|
||||||
|
Entity.LeftPropertyPath = LeftPropertyPath;
|
||||||
|
Entity.RightPropertyPath = RightPropertyPath;
|
||||||
|
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||||
|
|
||||||
|
Entity.OperatorPluginGuid = Operator?.PluginInfo?.Guid;
|
||||||
|
Entity.OperatorType = Operator?.GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Evaluate()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool EvaluateObject(object target)
|
||||||
|
{
|
||||||
|
return CompiledListPredicate != null && CompiledListPredicate(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Initialize(IDataModelService dataModelService)
|
||||||
|
{
|
||||||
|
// Left side
|
||||||
|
if (Entity.LeftPropertyPath != null && ListContainsInnerPath(Entity.LeftPropertyPath))
|
||||||
|
UpdateLeftSide(Entity.LeftPropertyPath);
|
||||||
|
|
||||||
|
// Operator
|
||||||
|
if (Entity.OperatorPluginGuid != null)
|
||||||
|
{
|
||||||
|
var conditionOperator = dataModelService.GetConditionOperator(Entity.OperatorPluginGuid.Value, Entity.OperatorType);
|
||||||
|
if (conditionOperator != null)
|
||||||
|
UpdateOperator(conditionOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right side dynamic
|
||||||
|
if (PredicateType == PredicateType.Dynamic && Entity.RightPropertyPath != null)
|
||||||
|
{
|
||||||
|
if (ListContainsInnerPath(Entity.RightPropertyPath))
|
||||||
|
UpdateLeftSide(Entity.LeftPropertyPath);
|
||||||
|
}
|
||||||
|
// Right side static
|
||||||
|
else if (PredicateType == PredicateType.Static && Entity.RightStaticValue != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (LeftPropertyPath != null)
|
||||||
|
{
|
||||||
|
// Use the left side type so JSON.NET has a better idea what to do
|
||||||
|
var leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
|
||||||
|
object rightSideValue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rightSideValue = JsonConvert.DeserializeObject(Entity.RightStaticValue, leftSideType);
|
||||||
|
}
|
||||||
|
// If deserialization fails, use the type's default
|
||||||
|
catch (JsonSerializationException e)
|
||||||
|
{
|
||||||
|
dataModelService.LogListPredicateDeserializationFailure(this, e);
|
||||||
|
rightSideValue = Activator.CreateInstance(leftSideType);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateRightSideStatic(rightSideValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Hope for the best... we must infer the type from JSON now
|
||||||
|
UpdateRightSideStatic(JsonConvert.DeserializeObject(Entity.RightStaticValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
dataModelService.LogListPredicateDeserializationFailure(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
|
{
|
||||||
|
return Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateOperator()
|
||||||
|
{
|
||||||
|
if (LeftPropertyPath == null || Operator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
|
||||||
|
if (!Operator.SupportsType(leftSideType))
|
||||||
|
Operator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateRightSide()
|
||||||
|
{
|
||||||
|
var leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
|
||||||
|
if (PredicateType == PredicateType.Dynamic)
|
||||||
|
{
|
||||||
|
if (RightPropertyPath == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var rightSideType = GetTypeAtInnerPath(RightPropertyPath);
|
||||||
|
if (!leftSideType.IsCastableFrom(rightSideType))
|
||||||
|
UpdateRightSideDynamic(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (RightStaticValue != null && leftSideType.IsCastableFrom(RightStaticValue.GetType()))
|
||||||
|
UpdateRightSideStatic(RightStaticValue);
|
||||||
|
else
|
||||||
|
UpdateRightSideStatic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetStaticValue(object staticValue)
|
||||||
|
{
|
||||||
|
// If the left side is empty simply apply the value, any validation will wait
|
||||||
|
if (LeftPropertyPath == null)
|
||||||
|
{
|
||||||
|
RightStaticValue = staticValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftSideType = GetTypeAtInnerPath(LeftPropertyPath);
|
||||||
|
|
||||||
|
// If not null ensure the types match and if not, convert it
|
||||||
|
if (staticValue != null && staticValue.GetType() == leftSideType)
|
||||||
|
RightStaticValue = staticValue;
|
||||||
|
else if (staticValue != null)
|
||||||
|
RightStaticValue = Convert.ChangeType(staticValue, leftSideType);
|
||||||
|
// If null create a default instance for value types or simply make it null for reference types
|
||||||
|
else if (leftSideType.IsValueType)
|
||||||
|
RightStaticValue = Activator.CreateInstance(leftSideType);
|
||||||
|
else
|
||||||
|
RightStaticValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateDynamicExpression()
|
||||||
|
{
|
||||||
|
if (LeftPropertyPath == null || RightPropertyPath == null || Operator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// List accessors share the same parameter because a list always contains one item per entry
|
||||||
|
var leftSideParameter = Expression.Parameter(typeof(object), "listItem");
|
||||||
|
var leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
|
||||||
|
var rightSideAccessor = CreateListAccessor(RightPropertyPath, leftSideParameter);
|
||||||
|
|
||||||
|
// A conversion may be required if the types differ
|
||||||
|
// This can cause issues if the DisplayConditionOperator wasn't accurate in it's supported types but that is not a concern here
|
||||||
|
if (rightSideAccessor.Type != leftSideAccessor.Type)
|
||||||
|
rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
|
||||||
|
|
||||||
|
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideAccessor);
|
||||||
|
var lambda = Expression.Lambda<Func<object, bool>>(conditionExpression, leftSideParameter);
|
||||||
|
CompiledListPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateStaticExpression()
|
||||||
|
{
|
||||||
|
if (LeftPropertyPath == null || Operator == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// List accessors share the same parameter because a list always contains one item per entry
|
||||||
|
var leftSideParameter = Expression.Parameter(typeof(object), "listItem");
|
||||||
|
var leftSideAccessor = CreateListAccessor(LeftPropertyPath, leftSideParameter);
|
||||||
|
|
||||||
|
// If the left side is a value type but the input is empty, this isn't a valid expression
|
||||||
|
if (leftSideAccessor.Type.IsValueType && RightStaticValue == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the right side value is null, the constant type cannot be inferred and must be provided manually
|
||||||
|
var rightSideConstant = RightStaticValue != null
|
||||||
|
? Expression.Constant(RightStaticValue)
|
||||||
|
: Expression.Constant(null, leftSideAccessor.Type);
|
||||||
|
|
||||||
|
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant);
|
||||||
|
var lambda = Expression.Lambda<Func<object, bool>>(conditionExpression, leftSideParameter);
|
||||||
|
CompiledListPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression CreateListAccessor(string path, ParameterExpression listParameter)
|
||||||
|
{
|
||||||
|
return path.Split('.').Aggregate<string, Expression>(
|
||||||
|
Expression.Convert(listParameter, ListType), // Cast to the appropriate type
|
||||||
|
Expression.Property
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ListContainsInnerPath(string path)
|
||||||
|
{
|
||||||
|
if (ListType == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var parts = path.Split('.');
|
||||||
|
var current = ListType;
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
var property = current.GetProperty(part);
|
||||||
|
current = property?.PropertyType;
|
||||||
|
|
||||||
|
if (property == null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetTypeAtInnerPath(string path)
|
||||||
|
{
|
||||||
|
if (!ListContainsInnerPath(path))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var parts = path.Split('.');
|
||||||
|
var current = ListType;
|
||||||
|
|
||||||
|
Type result = null;
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
var property = current.GetProperty(part);
|
||||||
|
current = property.PropertyType;
|
||||||
|
result = property.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,17 +18,17 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
PredicateType = predicateType;
|
PredicateType = predicateType;
|
||||||
DisplayConditionPredicateEntity = new DisplayConditionPredicateEntity();
|
Entity = new DisplayConditionPredicateEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionPredicate(DisplayConditionPart parent, DisplayConditionPredicateEntity entity)
|
public DisplayConditionPredicate(DisplayConditionPart parent, DisplayConditionPredicateEntity entity)
|
||||||
{
|
{
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
DisplayConditionPredicateEntity = entity;
|
Entity = entity;
|
||||||
PredicateType = (PredicateType) entity.PredicateType;
|
PredicateType = (PredicateType) entity.PredicateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionPredicateEntity DisplayConditionPredicateEntity { get; set; }
|
public DisplayConditionPredicateEntity Entity { get; set; }
|
||||||
|
|
||||||
public PredicateType PredicateType { get; set; }
|
public PredicateType PredicateType { get; set; }
|
||||||
public DisplayConditionOperator Operator { get; private set; }
|
public DisplayConditionOperator Operator { get; private set; }
|
||||||
@ -38,6 +38,8 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
public DataModel RightDataModel { get; private set; }
|
public DataModel RightDataModel { get; private set; }
|
||||||
public string RightPropertyPath { get; private set; }
|
public string RightPropertyPath { get; private set; }
|
||||||
public object RightStaticValue { get; private set; }
|
public object RightStaticValue { get; private set; }
|
||||||
|
public DataModel ListDataModel { get; private set; }
|
||||||
|
public string ListPropertyPath { get; private set; }
|
||||||
|
|
||||||
public Func<DataModel, DataModel, bool> CompiledDynamicPredicate { get; private set; }
|
public Func<DataModel, DataModel, bool> CompiledDynamicPredicate { get; private set; }
|
||||||
public Func<DataModel, bool> CompiledStaticPredicate { get; private set; }
|
public Func<DataModel, bool> CompiledStaticPredicate { get; private set; }
|
||||||
@ -135,16 +137,16 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
DisplayConditionPredicateEntity.PredicateType = (int) PredicateType;
|
Entity.PredicateType = (int) PredicateType;
|
||||||
DisplayConditionPredicateEntity.LeftDataModelGuid = LeftDataModel?.PluginInfo?.Guid;
|
Entity.LeftDataModelGuid = LeftDataModel?.PluginInfo?.Guid;
|
||||||
DisplayConditionPredicateEntity.LeftPropertyPath = LeftPropertyPath;
|
Entity.LeftPropertyPath = LeftPropertyPath;
|
||||||
|
|
||||||
DisplayConditionPredicateEntity.RightDataModelGuid = RightDataModel?.PluginInfo?.Guid;
|
Entity.RightDataModelGuid = RightDataModel?.PluginInfo?.Guid;
|
||||||
DisplayConditionPredicateEntity.RightPropertyPath = RightPropertyPath;
|
Entity.RightPropertyPath = RightPropertyPath;
|
||||||
DisplayConditionPredicateEntity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||||
|
|
||||||
DisplayConditionPredicateEntity.OperatorPluginGuid = Operator?.PluginInfo?.Guid;
|
Entity.OperatorPluginGuid = Operator?.PluginInfo?.Guid;
|
||||||
DisplayConditionPredicateEntity.OperatorType = Operator?.GetType().Name;
|
Entity.OperatorType = Operator?.GetType().Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Evaluate()
|
public override bool Evaluate()
|
||||||
@ -168,30 +170,30 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
internal override void Initialize(IDataModelService dataModelService)
|
internal override void Initialize(IDataModelService dataModelService)
|
||||||
{
|
{
|
||||||
// Left side
|
// Left side
|
||||||
if (DisplayConditionPredicateEntity.LeftDataModelGuid != null)
|
if (Entity.LeftDataModelGuid != null)
|
||||||
{
|
{
|
||||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.LeftDataModelGuid.Value);
|
var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.LeftDataModelGuid.Value);
|
||||||
if (dataModel != null && dataModel.ContainsPath(DisplayConditionPredicateEntity.LeftPropertyPath))
|
if (dataModel != null && dataModel.ContainsPath(Entity.LeftPropertyPath))
|
||||||
UpdateLeftSide(dataModel, DisplayConditionPredicateEntity.LeftPropertyPath);
|
UpdateLeftSide(dataModel, Entity.LeftPropertyPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operator
|
// Operator
|
||||||
if (DisplayConditionPredicateEntity.OperatorPluginGuid != null)
|
if (Entity.OperatorPluginGuid != null)
|
||||||
{
|
{
|
||||||
var conditionOperator = dataModelService.GetConditionOperator(DisplayConditionPredicateEntity.OperatorPluginGuid.Value, DisplayConditionPredicateEntity.OperatorType);
|
var conditionOperator = dataModelService.GetConditionOperator(Entity.OperatorPluginGuid.Value, Entity.OperatorType);
|
||||||
if (conditionOperator != null)
|
if (conditionOperator != null)
|
||||||
UpdateOperator(conditionOperator);
|
UpdateOperator(conditionOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right side dynamic
|
// Right side dynamic
|
||||||
if (PredicateType == PredicateType.Dynamic && DisplayConditionPredicateEntity.RightDataModelGuid != null)
|
if (PredicateType == PredicateType.Dynamic && Entity.RightDataModelGuid != null)
|
||||||
{
|
{
|
||||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.RightDataModelGuid.Value);
|
var dataModel = dataModelService.GetPluginDataModelByGuid(Entity.RightDataModelGuid.Value);
|
||||||
if (dataModel != null && dataModel.ContainsPath(DisplayConditionPredicateEntity.RightPropertyPath))
|
if (dataModel != null && dataModel.ContainsPath(Entity.RightPropertyPath))
|
||||||
UpdateRightSide(dataModel, DisplayConditionPredicateEntity.RightPropertyPath);
|
UpdateRightSide(dataModel, Entity.RightPropertyPath);
|
||||||
}
|
}
|
||||||
// Right side static
|
// Right side static
|
||||||
else if (PredicateType == PredicateType.Static && DisplayConditionPredicateEntity.RightStaticValue != null)
|
else if (PredicateType == PredicateType.Static && Entity.RightStaticValue != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -203,12 +205,12 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rightSideValue = JsonConvert.DeserializeObject(DisplayConditionPredicateEntity.RightStaticValue, leftSideType);
|
rightSideValue = JsonConvert.DeserializeObject(Entity.RightStaticValue, leftSideType);
|
||||||
}
|
}
|
||||||
// If deserialization fails, use the type's default
|
// If deserialization fails, use the type's default
|
||||||
catch (JsonSerializationException e)
|
catch (JsonSerializationException e)
|
||||||
{
|
{
|
||||||
dataModelService.LogDeserializationFailure(this, e);
|
dataModelService.LogPredicateDeserializationFailure(this, e);
|
||||||
rightSideValue = Activator.CreateInstance(leftSideType);
|
rightSideValue = Activator.CreateInstance(leftSideType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +219,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Hope for the best...
|
// Hope for the best...
|
||||||
UpdateRightSide(JsonConvert.DeserializeObject(DisplayConditionPredicateEntity.RightStaticValue));
|
UpdateRightSide(JsonConvert.DeserializeObject(Entity.RightStaticValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JsonReaderException)
|
catch (JsonReaderException)
|
||||||
@ -230,7 +232,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
internal override DisplayConditionPartEntity GetEntity()
|
internal override DisplayConditionPartEntity GetEntity()
|
||||||
{
|
{
|
||||||
return DisplayConditionPredicateEntity;
|
return Entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateOperator()
|
private void ValidateOperator()
|
||||||
@ -292,7 +294,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (LeftDataModel == null || RightDataModel == null || Operator == null)
|
if (LeftDataModel == null || RightDataModel == null || Operator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isListExpression = LeftDataModel.GetListTypeAtPath(LeftPropertyPath) != null;
|
var isListExpression = LeftDataModel.GetListTypeInPath(LeftPropertyPath) != null;
|
||||||
|
|
||||||
Expression leftSideAccessor;
|
Expression leftSideAccessor;
|
||||||
Expression rightSideAccessor;
|
Expression rightSideAccessor;
|
||||||
@ -335,7 +337,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (LeftDataModel == null || Operator == null)
|
if (LeftDataModel == null || Operator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isListExpression = LeftDataModel.GetListTypeAtPath(LeftPropertyPath) != null;
|
var isListExpression = LeftDataModel.GetListTypeInPath(LeftPropertyPath) != null;
|
||||||
|
|
||||||
Expression leftSideAccessor;
|
Expression leftSideAccessor;
|
||||||
ParameterExpression leftSideParameter;
|
ParameterExpression leftSideParameter;
|
||||||
@ -373,7 +375,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
private Expression CreateAccessor(DataModel dataModel, string path, string parameterName, out ParameterExpression parameter)
|
private Expression CreateAccessor(DataModel dataModel, string path, string parameterName, out ParameterExpression parameter)
|
||||||
{
|
{
|
||||||
var listType = dataModel.GetListTypeAtPath(path);
|
var listType = dataModel.GetListTypeInPath(path);
|
||||||
if (listType != null)
|
if (listType != null)
|
||||||
throw new ArtemisCoreException($"Cannot create a regular accessor at path {path} because the path contains a list");
|
throw new ArtemisCoreException($"Cannot create a regular accessor at path {path} because the path contains a list");
|
||||||
|
|
||||||
@ -386,7 +388,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
private Expression CreateListAccessor(DataModel dataModel, string path, ParameterExpression listParameter)
|
private Expression CreateListAccessor(DataModel dataModel, string path, ParameterExpression listParameter)
|
||||||
{
|
{
|
||||||
var listType = dataModel.GetListTypeAtPath(path);
|
var listType = dataModel.GetListTypeInPath(path);
|
||||||
if (listType == null)
|
if (listType == null)
|
||||||
throw new ArtemisCoreException($"Cannot create a list accessor at path {path} because the path does not contain a list");
|
throw new ArtemisCoreException($"Cannot create a list accessor at path {path} because the path does not contain a list");
|
||||||
|
|
||||||
|
|||||||
@ -299,7 +299,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
ApplyRenderElementToEntity();
|
ApplyRenderElementToEntity();
|
||||||
|
|
||||||
// Conditions
|
// Conditions
|
||||||
RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.DisplayConditionGroupEntity;
|
RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.Entity;
|
||||||
DisplayConditionGroup?.ApplyToEntity();
|
DisplayConditionGroup?.ApplyToEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -206,7 +206,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Conditions
|
// Conditions
|
||||||
RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.DisplayConditionGroupEntity;
|
RenderElementEntity.RootDisplayCondition = DisplayConditionGroup?.Entity;
|
||||||
DisplayConditionGroup?.ApplyToEntity();
|
DisplayConditionGroup?.ApplyToEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,14 +31,8 @@ namespace Artemis.Core.Plugins.Abstract.DataModels
|
|||||||
var current = GetType();
|
var current = GetType();
|
||||||
foreach (var part in parts)
|
foreach (var part in parts)
|
||||||
{
|
{
|
||||||
var property = current.GetProperty(part);
|
var property = current?.GetProperty(part);
|
||||||
|
|
||||||
// For lists, look into the list type instead of the list itself
|
|
||||||
if (property != null && typeof(IList).IsAssignableFrom(property.PropertyType))
|
|
||||||
current = property.PropertyType.GetGenericArguments()[0];
|
|
||||||
else
|
|
||||||
current = property?.PropertyType;
|
current = property?.PropertyType;
|
||||||
|
|
||||||
if (property == null)
|
if (property == null)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -58,20 +52,14 @@ namespace Artemis.Core.Plugins.Abstract.DataModels
|
|||||||
foreach (var part in parts)
|
foreach (var part in parts)
|
||||||
{
|
{
|
||||||
var property = current.GetProperty(part);
|
var property = current.GetProperty(part);
|
||||||
|
|
||||||
// For lists, look into the list type instead of the list itself
|
|
||||||
if (typeof(IList).IsAssignableFrom(property.PropertyType))
|
|
||||||
current = property.PropertyType.GetGenericArguments()[0];
|
|
||||||
else
|
|
||||||
current = property.PropertyType;
|
current = property.PropertyType;
|
||||||
|
|
||||||
result = property.PropertyType;
|
result = property.PropertyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type GetListTypeAtPath(string path)
|
public Type GetListTypeInPath(string path)
|
||||||
{
|
{
|
||||||
if (!ContainsPath(path))
|
if (!ContainsPath(path))
|
||||||
return null;
|
return null;
|
||||||
@ -79,8 +67,13 @@ namespace Artemis.Core.Plugins.Abstract.DataModels
|
|||||||
var parts = path.Split('.');
|
var parts = path.Split('.');
|
||||||
var current = GetType();
|
var current = GetType();
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
foreach (var part in parts)
|
foreach (var part in parts)
|
||||||
{
|
{
|
||||||
|
// Only return a type if the path CONTAINS a list, not if it points TO a list
|
||||||
|
if (index == parts.Length - 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
var property = current.GetProperty(part);
|
var property = current.GetProperty(part);
|
||||||
|
|
||||||
// For lists, look into the list type instead of the list itself
|
// For lists, look into the list type instead of the list itself
|
||||||
@ -88,14 +81,24 @@ namespace Artemis.Core.Plugins.Abstract.DataModels
|
|||||||
return property.PropertyType.GetGenericArguments()[0];
|
return property.PropertyType.GetGenericArguments()[0];
|
||||||
|
|
||||||
current = property.PropertyType;
|
current = property.PropertyType;
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type GetListTypeAtPath(string path)
|
||||||
|
{
|
||||||
|
if (!ContainsPath(path))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var child = GetTypeAtPath(path);
|
||||||
|
return child.GenericTypeArguments.Length > 0 ? child.GenericTypeArguments[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetListInnerPath(string path)
|
public string GetListInnerPath(string path)
|
||||||
{
|
{
|
||||||
if (GetListTypeAtPath(path) == null)
|
if (GetListTypeInPath(path) == null)
|
||||||
throw new ArtemisCoreException($"Cannot determine inner list path at {path} because it does not contain a list");
|
throw new ArtemisCoreException($"Cannot determine inner list path at {path} because it does not contain a list");
|
||||||
|
|
||||||
var parts = path.Split('.');
|
var parts = path.Split('.');
|
||||||
|
|||||||
@ -178,9 +178,27 @@ namespace Artemis.Core.Services
|
|||||||
return RegisteredConditionOperators.FirstOrDefault(o => o.PluginInfo.Guid == operatorPluginGuid && o.GetType().Name == operatorType);
|
return RegisteredConditionOperators.FirstOrDefault(o => o.PluginInfo.Guid == operatorPluginGuid && o.GetType().Name == operatorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonSerializationException exception)
|
public void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception)
|
||||||
{
|
{
|
||||||
_logger.Warning(exception, "Failed to deserialize display condition predicate {predicate}", displayConditionPredicate);
|
_logger.Warning(
|
||||||
|
exception,
|
||||||
|
"Failed to deserialize display condition predicate {left} {operator} {right}",
|
||||||
|
displayConditionPredicate.Entity.LeftPropertyPath,
|
||||||
|
displayConditionPredicate.Entity.OperatorType,
|
||||||
|
displayConditionPredicate.Entity.RightPropertyPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionPredicate, JsonException exception)
|
||||||
|
{
|
||||||
|
_logger.Warning(
|
||||||
|
exception,
|
||||||
|
"Failed to deserialize display condition list predicate {list} => {left} {operator} {right}",
|
||||||
|
displayConditionPredicate.Entity.ListPropertyPath,
|
||||||
|
displayConditionPredicate.Entity.LeftPropertyPath,
|
||||||
|
displayConditionPredicate.Entity.OperatorType,
|
||||||
|
displayConditionPredicate.Entity.RightPropertyPath
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterBuiltInConditionOperators()
|
private void RegisterBuiltInConditionOperators()
|
||||||
|
|||||||
@ -60,6 +60,7 @@ namespace Artemis.Core.Services.Interfaces
|
|||||||
|
|
||||||
List<DisplayConditionOperator> GetCompatibleConditionOperators(Type type);
|
List<DisplayConditionOperator> GetCompatibleConditionOperators(Type type);
|
||||||
DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType);
|
DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType);
|
||||||
void LogDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonSerializationException exception);
|
void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception);
|
||||||
|
void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionListPredicate, JsonException exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,8 +154,15 @@ namespace Artemis.Core.Services
|
|||||||
? new DisplayConditionGroup(null, renderElement.RenderElementEntity.RootDisplayCondition)
|
? new DisplayConditionGroup(null, renderElement.RenderElementEntity.RootDisplayCondition)
|
||||||
: new DisplayConditionGroup(null);
|
: new DisplayConditionGroup(null);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
displayCondition.Initialize(_dataModelService);
|
displayCondition.Initialize(_dataModelService);
|
||||||
renderElement.DisplayConditionGroup = displayCondition;
|
renderElement.DisplayConditionGroup = displayCondition;
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning(e, $"Failed to init display conditions for {renderElement}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile
|
||||||
|
{
|
||||||
|
public class DisplayConditionListEntity : DisplayConditionPartEntity
|
||||||
|
{
|
||||||
|
public DisplayConditionListEntity()
|
||||||
|
{
|
||||||
|
Children = new List<DisplayConditionPartEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid? ListDataModelGuid { get; set; }
|
||||||
|
public string ListPropertyPath { get; set; }
|
||||||
|
|
||||||
|
public int ListOperator { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile
|
namespace Artemis.Storage.Entities.Profile
|
||||||
{
|
{
|
||||||
public class DisplayConditionListPredicateEntity : DisplayConditionPartEntity
|
public class DisplayConditionListPredicateEntity : DisplayConditionPartEntity
|
||||||
{
|
{
|
||||||
public DisplayConditionListPredicateEntity()
|
public int PredicateType { get; set; }
|
||||||
{
|
|
||||||
Children = new List<DisplayConditionPartEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid? ListDataModelGuid { get; set; }
|
public Guid? ListDataModelGuid { get; set; }
|
||||||
public string ListPropertyPath { get; set; }
|
public string ListPropertyPath { get; set; }
|
||||||
|
|
||||||
public int ListOperator { get; set; }
|
public string LeftPropertyPath { get; set; }
|
||||||
|
public string RightPropertyPath { get; set; }
|
||||||
|
// Stored as a string to be able to control serialization and deserialization ourselves
|
||||||
|
public string RightStaticValue { get; set; }
|
||||||
|
|
||||||
|
public string OperatorType { get; set; }
|
||||||
|
public Guid? OperatorPluginGuid { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +208,6 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
var path = propertyPath.Split(".");
|
var path = propertyPath.Split(".");
|
||||||
var currentPart = path.First();
|
var currentPart = path.First();
|
||||||
|
|
||||||
if (IsRootViewModel)
|
if (IsRootViewModel)
|
||||||
{
|
{
|
||||||
var child = Children.FirstOrDefault(c => c.DataModel != null &&
|
var child = Children.FirstOrDefault(c => c.DataModel != null &&
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Artemis.UI.DataTemplateSelectors
|
||||||
|
{
|
||||||
|
// Source: https://stackoverflow.com/a/33421573/5015269
|
||||||
|
public class ComboBoxTemplateSelector : DataTemplateSelector
|
||||||
|
{
|
||||||
|
public DataTemplate SelectedItemTemplate { get; set; }
|
||||||
|
public DataTemplateSelector SelectedItemTemplateSelector { get; set; }
|
||||||
|
public DataTemplate DropdownItemsTemplate { get; set; }
|
||||||
|
public DataTemplateSelector DropdownItemsTemplateSelector { get; set; }
|
||||||
|
|
||||||
|
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
var itemToCheck = container;
|
||||||
|
|
||||||
|
// Search up the visual tree, stopping at either a ComboBox or
|
||||||
|
// a ComboBoxItem (or null). This will determine which template to use
|
||||||
|
while (itemToCheck != null && !(itemToCheck is ComboBoxItem) && !(itemToCheck is ComboBox))
|
||||||
|
itemToCheck = VisualTreeHelper.GetParent(itemToCheck);
|
||||||
|
|
||||||
|
// If you stopped at a ComboBoxItem, you're in the dropdown
|
||||||
|
var inDropDown = itemToCheck is ComboBoxItem;
|
||||||
|
|
||||||
|
return inDropDown
|
||||||
|
? DropdownItemsTemplate ?? DropdownItemsTemplateSelector?.SelectTemplate(item, container)
|
||||||
|
: SelectedItemTemplate ?? SelectedItemTemplateSelector?.SelectTemplate(item, container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ComboBoxTemplateSelectorExtension : MarkupExtension
|
||||||
|
{
|
||||||
|
public DataTemplate SelectedItemTemplate { get; set; }
|
||||||
|
public DataTemplateSelector SelectedItemTemplateSelector { get; set; }
|
||||||
|
public DataTemplate DropdownItemsTemplate { get; set; }
|
||||||
|
public DataTemplateSelector DropdownItemsTemplateSelector { get; set; }
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return new ComboBoxTemplateSelector()
|
||||||
|
{
|
||||||
|
SelectedItemTemplate = SelectedItemTemplate,
|
||||||
|
SelectedItemTemplateSelector = SelectedItemTemplateSelector,
|
||||||
|
DropdownItemsTemplate = DropdownItemsTemplate,
|
||||||
|
DropdownItemsTemplateSelector = DropdownItemsTemplateSelector
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -78,7 +78,7 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
public interface IDisplayConditionsVmFactory : IVmFactory
|
public interface IDisplayConditionsVmFactory : IVmFactory
|
||||||
{
|
{
|
||||||
DisplayConditionGroupViewModel DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent);
|
DisplayConditionGroupViewModel DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent);
|
||||||
DisplayConditionListPredicateViewModel DisplayConditionListPredicateViewModel(DisplayConditionListPredicate displayConditionListPredicate, DisplayConditionViewModel parent);
|
DisplayConditionListViewModel DisplayConditionListViewModel(DisplayConditionList displayConditionList, DisplayConditionViewModel parent);
|
||||||
DisplayConditionPredicateViewModel DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent);
|
DisplayConditionPredicateViewModel DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,17 +6,18 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
xmlns:propertyInput="clr-namespace:Artemis.UI.PropertyInput"
|
||||||
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
|
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
|
||||||
|
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance {x:Type propertyInput:BrushPropertyInputViewModel}}">
|
d:DataContext="{d:DesignInstance {x:Type propertyInput:BrushPropertyInputViewModel}}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ControlTemplate x:Key="SimpleTemplate">
|
<DataTemplate x:Key="SimpleTemplate">
|
||||||
<StackPanel d:DataContext="{d:DesignInstance {x:Type layerBrush:LayerBrushDescriptor}}" Orientation="Horizontal">
|
<StackPanel d:DataContext="{d:DesignInstance {x:Type layerBrush:LayerBrushDescriptor}}" Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon Kind="{Binding Icon}" Height="13" Width="13" Margin="0 1 3 0" />
|
<materialDesign:PackIcon Kind="{Binding Icon}" Height="13" Width="13" Margin="0 1 3 0" />
|
||||||
<TextBlock Text="{Binding DisplayName}" />
|
<TextBlock Text="{Binding DisplayName}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ControlTemplate>
|
</DataTemplate>
|
||||||
<ControlTemplate x:Key="ExtendedTemplate">
|
<DataTemplate x:Key="ExtendedTemplate">
|
||||||
<Grid d:DataContext="{d:DesignInstance {x:Type layerBrush:LayerBrushDescriptor}}">
|
<Grid d:DataContext="{d:DesignInstance {x:Type layerBrush:LayerBrushDescriptor}}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@ -30,15 +31,8 @@
|
|||||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding DisplayName}" TextWrapping="Wrap" MaxWidth="350" />
|
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding DisplayName}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}" TextWrapping="Wrap" MaxWidth="350" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}" TextWrapping="Wrap" MaxWidth="350" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
|
||||||
<DataTemplate x:Key="DescriptorTemplate">
|
|
||||||
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
|
|
||||||
<DataTemplate.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
|
||||||
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
|
|
||||||
</DataTrigger>
|
|
||||||
</DataTemplate.Triggers>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputPrefix}" />
|
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputPrefix}" />
|
||||||
@ -51,7 +45,9 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
ItemsSource="{Binding Path=Descriptors}"
|
ItemsSource="{Binding Path=Descriptors}"
|
||||||
SelectedValue="{Binding Path=SelectedDescriptor}"
|
SelectedValue="{Binding Path=SelectedDescriptor}"
|
||||||
ItemTemplate="{StaticResource DescriptorTemplate}" />
|
ItemTemplateSelector="{dataTemplateSelectors:ComboBoxTemplateSelector
|
||||||
|
SelectedItemTemplate={StaticResource SimpleTemplate},
|
||||||
|
DropdownItemsTemplate={StaticResource ExtendedTemplate}}" />
|
||||||
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
|
<TextBlock Width="10" Text="{Binding LayerProperty.PropertyDescription.InputAffix}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -71,7 +71,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
else if (type == "Dynamic")
|
else if (type == "Dynamic")
|
||||||
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic));
|
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic));
|
||||||
else if (type == "List")
|
else if (type == "List")
|
||||||
DisplayConditionGroup.AddChild(new DisplayConditionListPredicate(DisplayConditionGroup));
|
DisplayConditionGroup.AddChild(new DisplayConditionList(DisplayConditionGroup));
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
@ -108,8 +108,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
case DisplayConditionGroup displayConditionGroup:
|
case DisplayConditionGroup displayConditionGroup:
|
||||||
Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this));
|
Children.Add(_displayConditionsVmFactory.DisplayConditionGroupViewModel(displayConditionGroup, this));
|
||||||
break;
|
break;
|
||||||
case DisplayConditionListPredicate displayConditionListPredicate:
|
case DisplayConditionList displayConditionListPredicate:
|
||||||
Children.Add(_displayConditionsVmFactory.DisplayConditionListPredicateViewModel(displayConditionListPredicate, this));
|
Children.Add(_displayConditionsVmFactory.DisplayConditionListViewModel(displayConditionListPredicate, this));
|
||||||
break;
|
break;
|
||||||
case DisplayConditionPredicate displayConditionPredicate:
|
case DisplayConditionPredicate displayConditionPredicate:
|
||||||
Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this));
|
Children.Add(_displayConditionsVmFactory.DisplayConditionPredicateViewModel(displayConditionPredicate, this));
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionListPredicateView"
|
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionListView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -10,7 +10,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance Type=local:DisplayConditionListPredicateViewModel, IsDesignTimeCreatable=False}">
|
d:DataContext="{d:DesignInstance Type=local:DisplayConditionListViewModel, IsDesignTimeCreatable=False}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
@ -4,11 +4,11 @@ using System.Windows.Controls;
|
|||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for DisplayConditionListPredicateView.xaml
|
/// Interaction logic for DisplayConditionListView.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class DisplayConditionListPredicateView : UserControl
|
public partial class DisplayConditionListView : UserControl
|
||||||
{
|
{
|
||||||
public DisplayConditionListPredicateView()
|
public DisplayConditionListView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ using Humanizer;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
||||||
{
|
{
|
||||||
public class DisplayConditionListPredicateViewModel : DisplayConditionViewModel
|
public class DisplayConditionListViewModel : DisplayConditionViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IDataModelVisualizationService _dataModelVisualizationService;
|
private readonly IDataModelVisualizationService _dataModelVisualizationService;
|
||||||
@ -27,13 +27,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
private DataModelPropertiesViewModel _targetDataModel;
|
private DataModelPropertiesViewModel _targetDataModel;
|
||||||
private readonly Timer _updateTimer;
|
private readonly Timer _updateTimer;
|
||||||
|
|
||||||
public DisplayConditionListPredicateViewModel(
|
public DisplayConditionListViewModel(
|
||||||
DisplayConditionListPredicate displayConditionListPredicate,
|
DisplayConditionList displayConditionList,
|
||||||
DisplayConditionViewModel parent,
|
DisplayConditionViewModel parent,
|
||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IDataModelVisualizationService dataModelVisualizationService,
|
IDataModelVisualizationService dataModelVisualizationService,
|
||||||
IDisplayConditionsVmFactory displayConditionsVmFactory,
|
IDisplayConditionsVmFactory displayConditionsVmFactory,
|
||||||
ISettingsService settingsService) : base(displayConditionListPredicate, parent)
|
ISettingsService settingsService) : base(displayConditionList, parent)
|
||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_dataModelVisualizationService = dataModelVisualizationService;
|
_dataModelVisualizationService = dataModelVisualizationService;
|
||||||
@ -51,7 +51,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public DelegateCommand SelectListPropertyCommand { get; }
|
public DelegateCommand SelectListPropertyCommand { get; }
|
||||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||||
|
|
||||||
public DisplayConditionListPredicate DisplayConditionListPredicate => (DisplayConditionListPredicate) Model;
|
public DisplayConditionList DisplayConditionList => (DisplayConditionList) Model;
|
||||||
|
|
||||||
public bool IsInitialized
|
public bool IsInitialized
|
||||||
{
|
{
|
||||||
@ -73,21 +73,21 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
set => SetAndNotify(ref _selectedListProperty, value);
|
set => SetAndNotify(ref _selectedListProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SelectedListOperator => DisplayConditionListPredicate.ListOperator.Humanize();
|
public string SelectedListOperator => DisplayConditionList.ListOperator.Humanize();
|
||||||
|
|
||||||
public void SelectListOperator(string type)
|
public void SelectListOperator(string type)
|
||||||
{
|
{
|
||||||
var enumValue = Enum.Parse<ListOperator>(type);
|
var enumValue = Enum.Parse<ListOperator>(type);
|
||||||
DisplayConditionListPredicate.ListOperator = enumValue;
|
DisplayConditionList.ListOperator = enumValue;
|
||||||
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCondition(string type)
|
public void AddCondition(string type)
|
||||||
{
|
{
|
||||||
if (type == "Static")
|
if (type == "Static")
|
||||||
DisplayConditionListPredicate.AddChild(new DisplayConditionPredicate(DisplayConditionListPredicate, PredicateType.Static));
|
DisplayConditionList.AddChild(new DisplayConditionPredicate(DisplayConditionList, PredicateType.Static));
|
||||||
else if (type == "Dynamic")
|
else if (type == "Dynamic")
|
||||||
DisplayConditionListPredicate.AddChild(new DisplayConditionPredicate(DisplayConditionListPredicate, PredicateType.Dynamic));
|
DisplayConditionList.AddChild(new DisplayConditionPredicate(DisplayConditionList, PredicateType.Dynamic));
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
@ -95,7 +95,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
|
|
||||||
public void AddGroup()
|
public void AddGroup()
|
||||||
{
|
{
|
||||||
DisplayConditionListPredicate.AddChild(new DisplayConditionGroup(DisplayConditionListPredicate));
|
DisplayConditionList.AddChild(new DisplayConditionGroup(DisplayConditionList));
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
@ -146,7 +146,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
|
|
||||||
public void ApplyList()
|
public void ApplyList()
|
||||||
{
|
{
|
||||||
DisplayConditionListPredicate.UpdateList(SelectedListProperty.DataModel, SelectedListProperty.PropertyPath);
|
DisplayConditionList.UpdateList(SelectedListProperty.DataModel, SelectedListProperty.PropertyPath);
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
@ -155,7 +155,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public override DataModelPropertiesViewModel GetDataModelOverride()
|
public override DataModelPropertiesViewModel GetDataModelOverride()
|
||||||
{
|
{
|
||||||
if (SelectedListProperty != null)
|
if (SelectedListProperty != null)
|
||||||
return (DataModelPropertiesViewModel) SelectedListProperty.GetListTypeViewModel(_dataModelVisualizationService);
|
return SelectedListProperty.GetListTypeViewModel(_dataModelVisualizationService);
|
||||||
|
|
||||||
return base.GetDataModelOverride();
|
return base.GetDataModelOverride();
|
||||||
}
|
}
|
||||||
@ -168,9 +168,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
NotifyOfPropertyChange(nameof(SelectedListOperator));
|
||||||
|
|
||||||
// Update the selected list property
|
// Update the selected list property
|
||||||
if (DisplayConditionListPredicate.ListDataModel != null && DisplayConditionListPredicate.ListPropertyPath != null)
|
if (DisplayConditionList.ListDataModel != null && DisplayConditionList.ListPropertyPath != null)
|
||||||
{
|
{
|
||||||
var child = TargetDataModel.GetChildByPath(DisplayConditionListPredicate.ListDataModel.PluginInfo.Guid, DisplayConditionListPredicate.ListPropertyPath);
|
var child = TargetDataModel.GetChildByPath(
|
||||||
|
DisplayConditionList.ListDataModel.PluginInfo.Guid,
|
||||||
|
DisplayConditionList.ListPropertyPath
|
||||||
|
);
|
||||||
SelectedListProperty = child as DataModelListViewModel;
|
SelectedListProperty = child as DataModelListViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +181,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
|
TargetDataModel.ApplyTypeFilter(true, typeof(IList));
|
||||||
|
|
||||||
// Remove VMs of effects no longer applied on the layer
|
// Remove VMs of effects no longer applied on the layer
|
||||||
var toRemove = Children.Where(c => !DisplayConditionListPredicate.Children.Contains(c.Model)).ToList();
|
var toRemove = Children.Where(c => !DisplayConditionList.Children.Contains(c.Model)).ToList();
|
||||||
// Using RemoveRange breaks our lovely animations
|
// Using RemoveRange breaks our lovely animations
|
||||||
foreach (var displayConditionViewModel in toRemove)
|
foreach (var displayConditionViewModel in toRemove)
|
||||||
{
|
{
|
||||||
@ -8,12 +8,10 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||||
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
|
|
||||||
x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionPredicateView"
|
x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionPredicateView"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type local:DisplayConditionPredicateViewModel}}"
|
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type local:DisplayConditionPredicateViewModel}}">
|
||||||
x:Name="DisplayConditionPredicateRoot">
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||||
xmlns:profile="clr-namespace:Artemis.Core.Models.Profile;assembly=Artemis.Core"
|
xmlns:profile="clr-namespace:Artemis.Core.Models.Profile;assembly=Artemis.Core"
|
||||||
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
|
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
|
||||||
|
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True"
|
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
@ -22,12 +23,12 @@
|
|||||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<ControlTemplate x:Key="SimpleTemplate">
|
<DataTemplate x:Key="SimpleTemplate">
|
||||||
<StackPanel d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}" Orientation="Horizontal">
|
<StackPanel d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}" Orientation="Horizontal">
|
||||||
<TextBlock Text="{Binding Name}" />
|
<TextBlock Text="{Binding Name}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ControlTemplate>
|
</DataTemplate>
|
||||||
<ControlTemplate x:Key="ExtendedTemplate">
|
<DataTemplate x:Key="ExtendedTemplate">
|
||||||
<Grid d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}">
|
<Grid d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@ -44,14 +45,6 @@
|
|||||||
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" HorizontalAlignment="Right" />
|
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" HorizontalAlignment="Right" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
|
||||||
<DataTemplate x:Key="ProfileDescriptorTemplate">
|
|
||||||
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
|
|
||||||
<DataTemplate.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
|
||||||
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
|
|
||||||
</DataTrigger>
|
|
||||||
</DataTemplate.Triggers>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -138,7 +131,9 @@
|
|||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
ItemsSource="{Binding Profiles}"
|
ItemsSource="{Binding Profiles}"
|
||||||
SelectedItem="{Binding SelectedProfile}"
|
SelectedItem="{Binding SelectedProfile}"
|
||||||
ItemTemplate="{StaticResource ProfileDescriptorTemplate}">
|
ItemTemplateSelector="{dataTemplateSelectors:ComboBoxTemplateSelector
|
||||||
|
SelectedItemTemplate={StaticResource SimpleTemplate},
|
||||||
|
DropdownItemsTemplate={StaticResource ExtendedTemplate}}" >
|
||||||
<ComboBox.ItemsPanel>
|
<ComboBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<VirtualizingStackPanel />
|
<VirtualizingStackPanel />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user