mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-31 17:53:32 +00:00
Display conditions - Implemented lists in the core, UI needs more work
This commit is contained in:
parent
ae708fa26a
commit
f2f77da953
@ -35,8 +35,19 @@ namespace Artemis.Core.Models.Profile.Conditions.Abstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates the condition part on the data model
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public abstract bool Evaluate();
|
public abstract bool Evaluate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates the condition part on the given target (currently only for lists)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract bool EvaluateObject(object target);
|
||||||
|
|
||||||
internal abstract void Initialize(IDataModelService dataModelService);
|
internal abstract void Initialize(IDataModelService dataModelService);
|
||||||
internal abstract void ApplyToEntity();
|
internal abstract void ApplyToEntity();
|
||||||
internal abstract DisplayConditionPartEntity GetEntity();
|
internal abstract DisplayConditionPartEntity GetEntity();
|
||||||
|
|||||||
@ -37,9 +37,12 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
public override bool Evaluate()
|
public override bool Evaluate()
|
||||||
{
|
{
|
||||||
// If there are less than two children, ignore the boolean operator
|
// Empty groups are always true
|
||||||
if (Children.Count <= 2)
|
if (Children.Count == 0)
|
||||||
return Children.All(c => c.Evaluate());
|
return true;
|
||||||
|
// Groups with only one child ignore the boolean operator
|
||||||
|
if (Children.Count == 1)
|
||||||
|
return Children[0].Evaluate();
|
||||||
|
|
||||||
switch (BooleanOperator)
|
switch (BooleanOperator)
|
||||||
{
|
{
|
||||||
@ -56,6 +59,25 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool EvaluateObject(object target)
|
||||||
|
{
|
||||||
|
// Empty groups are always true
|
||||||
|
if (Children.Count == 0)
|
||||||
|
return true;
|
||||||
|
// Groups with only one child ignore the boolean operator
|
||||||
|
if (Children.Count == 1)
|
||||||
|
return Children[0].EvaluateObject(target);
|
||||||
|
|
||||||
|
return BooleanOperator switch
|
||||||
|
{
|
||||||
|
BooleanOperator.And => Children.All(c => c.EvaluateObject(target)),
|
||||||
|
BooleanOperator.Or => Children.Any(c => c.EvaluateObject(target)),
|
||||||
|
BooleanOperator.AndNot => Children.All(c => !c.EvaluateObject(target)),
|
||||||
|
BooleanOperator.OrNot => Children.Any(c => !c.EvaluateObject(target)),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator;
|
DisplayConditionGroupEntity.BooleanOperator = (int) BooleanOperator;
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using Artemis.Core.Exceptions;
|
using Artemis.Core.Exceptions;
|
||||||
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;
|
||||||
@ -44,7 +47,23 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
public override bool Evaluate()
|
public override bool Evaluate()
|
||||||
{
|
{
|
||||||
return true;
|
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()
|
internal override void ApplyToEntity()
|
||||||
@ -94,11 +113,26 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
{
|
{
|
||||||
if (!dataModel.ContainsPath(path))
|
if (!dataModel.ContainsPath(path))
|
||||||
throw new ArtemisCoreException($"Data model of type {dataModel.GetType().Name} does not contain a property at path '{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;
|
ListDataModel = dataModel;
|
||||||
ListPropertyPath = path;
|
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
|
public enum ListOperator
|
||||||
|
|||||||
@ -39,10 +39,9 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
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 Expression<Func<DataModel, DataModel, bool>> DynamicConditionLambda { get; private set; }
|
public Func<DataModel, DataModel, bool> CompiledDynamicPredicate { get; private set; }
|
||||||
public Func<DataModel, DataModel, bool> CompiledDynamicConditionLambda { get; private set; }
|
public Func<DataModel, bool> CompiledStaticPredicate { get; private set; }
|
||||||
public Expression<Func<DataModel, bool>> StaticConditionLambda { get; private set; }
|
public Func<object, bool> CompiledListPredicate { get; private set; }
|
||||||
public Func<DataModel, bool> CompiledStaticConditionLambda { get; private set; }
|
|
||||||
|
|
||||||
public void UpdateLeftSide(DataModel dataModel, string path)
|
public void UpdateLeftSide(DataModel dataModel, string path)
|
||||||
{
|
{
|
||||||
@ -120,10 +119,9 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
private void CreateExpression()
|
private void CreateExpression()
|
||||||
{
|
{
|
||||||
DynamicConditionLambda = null;
|
CompiledDynamicPredicate = null;
|
||||||
CompiledDynamicConditionLambda = null;
|
CompiledStaticPredicate = null;
|
||||||
StaticConditionLambda = null;
|
CompiledListPredicate = null;
|
||||||
CompiledStaticConditionLambda = null;
|
|
||||||
|
|
||||||
if (Operator == null)
|
if (Operator == null)
|
||||||
return;
|
return;
|
||||||
@ -137,7 +135,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
DisplayConditionPredicateEntity.PredicateType = (int)PredicateType;
|
DisplayConditionPredicateEntity.PredicateType = (int) PredicateType;
|
||||||
DisplayConditionPredicateEntity.LeftDataModelGuid = LeftDataModel?.PluginInfo?.Guid;
|
DisplayConditionPredicateEntity.LeftDataModelGuid = LeftDataModel?.PluginInfo?.Guid;
|
||||||
DisplayConditionPredicateEntity.LeftPropertyPath = LeftPropertyPath;
|
DisplayConditionPredicateEntity.LeftPropertyPath = LeftPropertyPath;
|
||||||
|
|
||||||
@ -151,10 +149,18 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
public override bool Evaluate()
|
public override bool Evaluate()
|
||||||
{
|
{
|
||||||
if (CompiledDynamicConditionLambda != null)
|
if (CompiledDynamicPredicate != null)
|
||||||
return CompiledDynamicConditionLambda(LeftDataModel, RightDataModel);
|
return CompiledDynamicPredicate(LeftDataModel, RightDataModel);
|
||||||
if (CompiledStaticConditionLambda != null)
|
if (CompiledStaticPredicate != null)
|
||||||
return CompiledStaticConditionLambda(LeftDataModel);
|
return CompiledStaticPredicate(LeftDataModel);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool EvaluateObject(object target)
|
||||||
|
{
|
||||||
|
if (CompiledListPredicate != null)
|
||||||
|
return CompiledListPredicate(target);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -286,26 +292,42 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (LeftDataModel == null || RightDataModel == null || Operator == null)
|
if (LeftDataModel == null || RightDataModel == null || Operator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var leftSideParameter = Expression.Parameter(typeof(DataModel), "leftDataModel");
|
var isListExpression = LeftDataModel.GetListTypeAtPath(LeftPropertyPath) != null;
|
||||||
var leftSideAccessor = LeftPropertyPath.Split('.').Aggregate<string, Expression>(
|
|
||||||
Expression.Convert(leftSideParameter, LeftDataModel.GetType()), // Cast to the appropriate type
|
Expression leftSideAccessor;
|
||||||
Expression.Property
|
Expression rightSideAccessor;
|
||||||
);
|
ParameterExpression leftSideParameter;
|
||||||
var rightSideParameter = Expression.Parameter(typeof(DataModel), "rightDataModel");
|
ParameterExpression rightSideParameter = null;
|
||||||
var rightSideAccessor = RightPropertyPath.Split('.').Aggregate<string, Expression>(
|
if (isListExpression)
|
||||||
Expression.Convert(rightSideParameter, LeftDataModel.GetType()), // Cast to the appropriate type
|
{
|
||||||
Expression.Property
|
// List accessors share the same parameter because a list always contains one item per entry
|
||||||
);
|
leftSideParameter = Expression.Parameter(typeof(object), "listItem");
|
||||||
|
leftSideAccessor = CreateListAccessor(LeftDataModel, LeftPropertyPath, leftSideParameter);
|
||||||
|
rightSideAccessor = CreateListAccessor(RightDataModel, RightPropertyPath, leftSideParameter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
leftSideAccessor = CreateAccessor(LeftDataModel, LeftPropertyPath, "left", out leftSideParameter);
|
||||||
|
rightSideAccessor = CreateAccessor(RightDataModel, RightPropertyPath, "right", out rightSideParameter);
|
||||||
|
}
|
||||||
|
|
||||||
// A conversion may be required if the types differ
|
// 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
|
// 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)
|
if (rightSideAccessor.Type != leftSideAccessor.Type)
|
||||||
rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
|
rightSideAccessor = Expression.Convert(rightSideAccessor, leftSideAccessor.Type);
|
||||||
|
|
||||||
var dynamicConditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideAccessor);
|
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideAccessor);
|
||||||
|
|
||||||
DynamicConditionLambda = Expression.Lambda<Func<DataModel, DataModel, bool>>(dynamicConditionExpression, leftSideParameter, rightSideParameter);
|
if (isListExpression)
|
||||||
CompiledDynamicConditionLambda = DynamicConditionLambda.Compile();
|
{
|
||||||
|
var lambda = Expression.Lambda<Func<object, bool>>(conditionExpression, leftSideParameter);
|
||||||
|
CompiledListPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var lambda = Expression.Lambda<Func<DataModel, DataModel, bool>>(conditionExpression, leftSideParameter, rightSideParameter);
|
||||||
|
CompiledDynamicPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateStaticExpression()
|
private void CreateStaticExpression()
|
||||||
@ -313,11 +335,18 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (LeftDataModel == null || Operator == null)
|
if (LeftDataModel == null || Operator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var leftSideParameter = Expression.Parameter(typeof(DataModel), "leftDataModel");
|
var isListExpression = LeftDataModel.GetListTypeAtPath(LeftPropertyPath) != null;
|
||||||
var leftSideAccessor = LeftPropertyPath.Split('.').Aggregate<string, Expression>(
|
|
||||||
Expression.Convert(leftSideParameter, LeftDataModel.GetType()), // Cast to the appropriate type
|
Expression leftSideAccessor;
|
||||||
Expression.Property
|
ParameterExpression leftSideParameter;
|
||||||
);
|
if (isListExpression)
|
||||||
|
{
|
||||||
|
// List accessors share the same parameter because a list always contains one item per entry
|
||||||
|
leftSideParameter = Expression.Parameter(typeof(object), "listItem");
|
||||||
|
leftSideAccessor = CreateListAccessor(LeftDataModel, LeftPropertyPath, leftSideParameter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
leftSideAccessor = CreateAccessor(LeftDataModel, LeftPropertyPath, "left", out leftSideParameter);
|
||||||
|
|
||||||
// If the left side is a value type but the input is empty, this isn't a valid expression
|
// 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)
|
if (leftSideAccessor.Type.IsValueType && RightStaticValue == null)
|
||||||
@ -330,8 +359,42 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
|
|
||||||
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant);
|
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant);
|
||||||
|
|
||||||
StaticConditionLambda = Expression.Lambda<Func<DataModel, bool>>(conditionExpression, leftSideParameter);
|
if (isListExpression)
|
||||||
CompiledStaticConditionLambda = StaticConditionLambda.Compile();
|
{
|
||||||
|
var lambda = Expression.Lambda<Func<object, bool>>(conditionExpression, leftSideParameter);
|
||||||
|
CompiledListPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var lambda = Expression.Lambda<Func<DataModel, bool>>(conditionExpression, leftSideParameter);
|
||||||
|
CompiledStaticPredicate = lambda.Compile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression CreateAccessor(DataModel dataModel, string path, string parameterName, out ParameterExpression parameter)
|
||||||
|
{
|
||||||
|
var listType = dataModel.GetListTypeAtPath(path);
|
||||||
|
if (listType != null)
|
||||||
|
throw new ArtemisCoreException($"Cannot create a regular accessor at path {path} because the path contains a list");
|
||||||
|
|
||||||
|
parameter = Expression.Parameter(typeof(object), parameterName + "DataModel");
|
||||||
|
return path.Split('.').Aggregate<string, Expression>(
|
||||||
|
Expression.Convert(parameter, dataModel.GetType()), // Cast to the appropriate type
|
||||||
|
Expression.Property
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression CreateListAccessor(DataModel dataModel, string path, ParameterExpression listParameter)
|
||||||
|
{
|
||||||
|
var listType = dataModel.GetListTypeAtPath(path);
|
||||||
|
if (listType == null)
|
||||||
|
throw new ArtemisCoreException($"Cannot create a list accessor at path {path} because the path does not contain a list");
|
||||||
|
|
||||||
|
path = dataModel.GetListInnerPath(path);
|
||||||
|
return path.Split('.').Aggregate<string, Expression>(
|
||||||
|
Expression.Convert(listParameter, listType), // Cast to the appropriate type
|
||||||
|
Expression.Property
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using Artemis.Core.Exceptions;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
|
|
||||||
@ -27,8 +31,14 @@ 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);
|
||||||
current = property?.PropertyType;
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
if (property == null)
|
if (property == null)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -48,13 +58,63 @@ 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);
|
||||||
current = property.PropertyType;
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
result = property.PropertyType;
|
result = property.PropertyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type GetListTypeAtPath(string path)
|
||||||
|
{
|
||||||
|
if (!ContainsPath(path))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var parts = path.Split('.');
|
||||||
|
var current = GetType();
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
var property = current.GetProperty(part);
|
||||||
|
|
||||||
|
// For lists, look into the list type instead of the list itself
|
||||||
|
if (typeof(IList).IsAssignableFrom(property.PropertyType))
|
||||||
|
return property.PropertyType.GetGenericArguments()[0];
|
||||||
|
|
||||||
|
current = property.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetListInnerPath(string path)
|
||||||
|
{
|
||||||
|
if (GetListTypeAtPath(path) == null)
|
||||||
|
throw new ArtemisCoreException($"Cannot determine inner list path at {path} because it does not contain a list");
|
||||||
|
|
||||||
|
var parts = path.Split('.');
|
||||||
|
var current = GetType();
|
||||||
|
|
||||||
|
for (var index = 0; index < parts.Length; index++)
|
||||||
|
{
|
||||||
|
var part = parts[index];
|
||||||
|
var property = current.GetProperty(part);
|
||||||
|
|
||||||
|
if (typeof(IList).IsAssignableFrom(property.PropertyType))
|
||||||
|
return string.Join('.', parts.Skip(index + 1).ToList());
|
||||||
|
|
||||||
|
current = property.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a read-only list of all properties in this datamodel that are to be ignored
|
/// Returns a read-only list of all properties in this datamodel that are to be ignored
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -34,6 +34,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
set => SetAndNotify(ref _displayValue, value);
|
set => SetAndNotify(ref _displayValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string PropertyPath => Parent?.PropertyPath;
|
||||||
|
|
||||||
|
public override string DisplayPropertyPath => Parent?.DisplayPropertyPath;
|
||||||
|
|
||||||
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
{
|
{
|
||||||
// Display value gets updated by parent, don't do anything if it is null
|
// Display value gets updated by parent, don't do anything if it is null
|
||||||
|
|||||||
@ -3,7 +3,6 @@ using System.Collections;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Artemis.Core.Extensions;
|
using Artemis.Core.Extensions;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
@ -26,12 +25,6 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
set => SetAndNotify(ref _list, value);
|
set => SetAndNotify(ref _list, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataModelVisualizationViewModel ListTypePropertyViewModel
|
|
||||||
{
|
|
||||||
get => _listTypePropertyViewModel;
|
|
||||||
set => SetAndNotify(ref _listTypePropertyViewModel, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BindableCollection<DataModelVisualizationViewModel> ListChildren { get; set; }
|
public BindableCollection<DataModelVisualizationViewModel> ListChildren { get; set; }
|
||||||
|
|
||||||
public string Count
|
public string Count
|
||||||
@ -40,6 +33,30 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
set => SetAndNotify(ref _count, value);
|
set => SetAndNotify(ref _count, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataModelPropertiesViewModel GetListTypeViewModel(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
|
{
|
||||||
|
// Create a property VM describing the type of the list
|
||||||
|
var viewModel = CreateListChild(dataModelVisualizationService, List.GetType().GenericTypeArguments[0]);
|
||||||
|
|
||||||
|
// Put an empty value into the list type property view model
|
||||||
|
if (viewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
|
||||||
|
{
|
||||||
|
dataModelListClassViewModel.DisplayValue = Activator.CreateInstance(dataModelListClassViewModel.ListType);
|
||||||
|
dataModelListClassViewModel.Update(dataModelVisualizationService);
|
||||||
|
return dataModelListClassViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel is DataModelListPropertyViewModel dataModelListPropertyViewModel)
|
||||||
|
{
|
||||||
|
dataModelListPropertyViewModel.DisplayValue = Activator.CreateInstance(dataModelListPropertyViewModel.ListType);
|
||||||
|
var wrapper = new DataModelPropertiesViewModel(null,null,null);
|
||||||
|
wrapper.Children.Add(dataModelListPropertyViewModel);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
{
|
{
|
||||||
if (Parent != null && !Parent.IsVisualizationExpanded)
|
if (Parent != null && !Parent.IsVisualizationExpanded)
|
||||||
@ -49,20 +66,6 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
if (List == null)
|
if (List == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ListTypePropertyViewModel == null)
|
|
||||||
{
|
|
||||||
// Create a property VM describing the type of the list
|
|
||||||
ListTypePropertyViewModel = CreateListChild(dataModelVisualizationService, List.GetType().GenericTypeArguments[0]);
|
|
||||||
|
|
||||||
// Put an empty value into the list type property view model
|
|
||||||
if (ListTypePropertyViewModel is DataModelListPropertiesViewModel dataModelListClassViewModel)
|
|
||||||
dataModelListClassViewModel.DisplayValue = Activator.CreateInstance(dataModelListClassViewModel.ListType);
|
|
||||||
else if (ListTypePropertyViewModel is DataModelListPropertyViewModel dataModelListPropertyViewModel)
|
|
||||||
dataModelListPropertyViewModel.DisplayValue = Activator.CreateInstance(dataModelListPropertyViewModel.ListType);
|
|
||||||
|
|
||||||
ListTypePropertyViewModel.Update(dataModelVisualizationService);
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = 0;
|
var index = 0;
|
||||||
foreach (var item in List)
|
foreach (var item in List)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Windows.Documents;
|
||||||
using Artemis.Core.Extensions;
|
using Artemis.Core.Extensions;
|
||||||
using Artemis.Core.Models.Profile.Conditions;
|
using Artemis.Core.Models.Profile.Conditions;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||||
using Artemis.UI.Shared.Exceptions;
|
using Artemis.UI.Shared.Exceptions;
|
||||||
@ -26,7 +25,6 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
private DataModelVisualizationViewModel _parent;
|
private DataModelVisualizationViewModel _parent;
|
||||||
private DataModelPropertyAttribute _propertyDescription;
|
private DataModelPropertyAttribute _propertyDescription;
|
||||||
private PropertyInfo _propertyInfo;
|
private PropertyInfo _propertyInfo;
|
||||||
private bool _isIgnored;
|
|
||||||
|
|
||||||
internal DataModelVisualizationViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, PropertyInfo propertyInfo)
|
internal DataModelVisualizationViewModel(DataModel dataModel, DataModelVisualizationViewModel parent, PropertyInfo propertyInfo)
|
||||||
{
|
{
|
||||||
@ -91,7 +89,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PropertyPath
|
public virtual string PropertyPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -106,7 +104,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DisplayPropertyPath
|
public virtual string DisplayPropertyPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -213,12 +211,14 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
if (IsRootViewModel)
|
if (IsRootViewModel)
|
||||||
{
|
{
|
||||||
var child = Children.FirstOrDefault(c => c.DataModel.PluginInfo.Guid == dataModelGuid);
|
var child = Children.FirstOrDefault(c => c.DataModel != null &&
|
||||||
|
c.DataModel.PluginInfo.Guid == dataModelGuid);
|
||||||
return child?.GetChildByPath(dataModelGuid, propertyPath);
|
return child?.GetChildByPath(dataModelGuid, propertyPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var child = Children.FirstOrDefault(c => c.DataModel.PluginInfo.Guid == dataModelGuid && c.PropertyInfo?.Name == currentPart);
|
var child = Children.FirstOrDefault(c => c.DataModel != null &&
|
||||||
|
c.DataModel.PluginInfo.Guid == dataModelGuid && c.PropertyInfo?.Name == currentPart);
|
||||||
if (child == null)
|
if (child == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
|
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:s="https://github.com/canton7/Stylet">
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Converters">
|
||||||
<Style x:Key="DisplayConditionButton" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatAccentBgButton}">
|
<Style x:Key="DisplayConditionButton" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatAccentBgButton}">
|
||||||
<Setter Property="Margin" Value="3 0" />
|
<Setter Property="Margin" Value="3 0" />
|
||||||
<Setter Property="Padding" Value="6 4" />
|
<Setter Property="Padding" Value="6 4" />
|
||||||
@ -90,7 +91,6 @@
|
|||||||
Margin="15 0.5 0 0"
|
Margin="15 0.5 0 0"
|
||||||
Visibility="{Binding ShowViewModel, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
Visibility="{Binding ShowViewModel, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</StackPanel.Resources>
|
</StackPanel.Resources>
|
||||||
|
|||||||
@ -30,11 +30,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract
|
|||||||
|
|
||||||
public abstract void Update();
|
public abstract void Update();
|
||||||
|
|
||||||
public virtual List<DataModelVisualizationViewModel> GetExtraDataModels()
|
public virtual DataModelPropertiesViewModel GetDataModelOverride()
|
||||||
{
|
{
|
||||||
if (Parent != null)
|
return Parent?.GetDataModelOverride();
|
||||||
return Parent.GetExtraDataModels();
|
|
||||||
return new List<DataModelVisualizationViewModel>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Delete()
|
public virtual void Delete()
|
||||||
|
|||||||
@ -152,13 +152,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<DataModelVisualizationViewModel> GetExtraDataModels()
|
public override DataModelPropertiesViewModel GetDataModelOverride()
|
||||||
{
|
{
|
||||||
var list = base.GetExtraDataModels();
|
|
||||||
if (SelectedListProperty != null)
|
if (SelectedListProperty != null)
|
||||||
list.Add(SelectedListProperty.ListTypePropertyViewModel);
|
return (DataModelPropertiesViewModel) SelectedListProperty.GetListTypeViewModel(_dataModelVisualizationService);
|
||||||
|
|
||||||
return list;
|
return base.GetDataModelOverride();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
@ -210,9 +209,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
SelectedListProperty = dataModelListViewModel;
|
SelectedListProperty = dataModelListViewModel;
|
||||||
if (SelectedListProperty.ListTypePropertyViewModel == null)
|
|
||||||
SelectedListProperty.Update(_dataModelVisualizationService);
|
|
||||||
|
|
||||||
ApplyList();
|
ApplyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -202,6 +202,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
if (LeftSideDataModel == null || DisplayConditionPredicate.PredicateType == PredicateType.Dynamic && RightSideDataModel == null)
|
if (LeftSideDataModel == null || DisplayConditionPredicate.PredicateType == PredicateType.Dynamic && RightSideDataModel == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (GetDataModelOverride() != null)
|
||||||
|
LeftSideDataModel = GetDataModelOverride();
|
||||||
|
|
||||||
// If static, only allow selecting properties also supported by input
|
// If static, only allow selecting properties also supported by input
|
||||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Static)
|
if (DisplayConditionPredicate.PredicateType == PredicateType.Static)
|
||||||
LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray());
|
LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray());
|
||||||
@ -221,6 +224,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic)
|
if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic)
|
||||||
{
|
{
|
||||||
SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right);
|
SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right);
|
||||||
|
if (GetDataModelOverride() != null)
|
||||||
|
RightSideDataModel = GetDataModelOverride();
|
||||||
|
|
||||||
RightSideDataModel.ApplyTypeFilter(true, leftSideType);
|
RightSideDataModel.ApplyTypeFilter(true, leftSideType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General.DataModel
|
namespace Artemis.Plugins.Modules.General.DataModel
|
||||||
@ -10,6 +11,12 @@ namespace Artemis.Plugins.Modules.General.DataModel
|
|||||||
{
|
{
|
||||||
TimeDataModel = new TimeDataModel();
|
TimeDataModel = new TimeDataModel();
|
||||||
TestTimeList = new List<TimeDataModel>();
|
TestTimeList = new List<TimeDataModel>();
|
||||||
|
|
||||||
|
var testExpression = new Func<object, object, bool>((leftItem, rightDataModel) =>
|
||||||
|
((TimeDataModel) leftItem).CurrentTime.Month == ((GeneralDataModel) rightDataModel).TimeDataModel.CurrentTime.Day);
|
||||||
|
|
||||||
|
|
||||||
|
var test = TestTimeList.Any(model => testExpression(model, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public WindowDataModel ActiveWindow { get; set; }
|
public WindowDataModel ActiveWindow { get; set; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user