mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Data model conditions - DRY'd predicate code in preparation for events
This commit is contained in:
parent
a79223fa75
commit
574c4b21ec
@ -9,20 +9,19 @@ namespace Artemis.Core
|
||||
/// A predicate in a data model condition using either two data model values or one data model value and a
|
||||
/// static value
|
||||
/// </summary>
|
||||
public class DataModelConditionPredicate : DataModelConditionPart
|
||||
public abstract class DataModelConditionPredicate : DataModelConditionPart
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModelConditionPredicate" /> class
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="predicateType"></param>
|
||||
public DataModelConditionPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
|
||||
/// <param name="entity">A new empty entity</param>
|
||||
protected DataModelConditionPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType, DataModelConditionPredicateEntity entity)
|
||||
{
|
||||
Parent = parent;
|
||||
Entity = entity;
|
||||
PredicateType = predicateType;
|
||||
Entity = new DataModelConditionPredicateEntity();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal DataModelConditionPredicate(DataModelConditionPart parent, DataModelConditionPredicateEntity entity)
|
||||
@ -30,8 +29,6 @@ namespace Artemis.Core
|
||||
Parent = parent;
|
||||
Entity = entity;
|
||||
PredicateType = (ProfileRightSideType) entity.PredicateType;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -42,31 +39,117 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets the operator
|
||||
/// </summary>
|
||||
public BaseConditionOperator? Operator { get; private set; }
|
||||
public BaseConditionOperator? Operator { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the left property
|
||||
/// </summary>
|
||||
public DataModelPath? LeftPath { get; private set; }
|
||||
public DataModelPath? LeftPath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the right property
|
||||
/// </summary>
|
||||
public DataModelPath? RightPath { get; private set; }
|
||||
public DataModelPath? RightPath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right static value, only used it <see cref="PredicateType" /> is
|
||||
/// <see cref="ProfileRightSideType.Static" />
|
||||
/// </summary>
|
||||
public object? RightStaticValue { get; private set; }
|
||||
public object? RightStaticValue { get; protected set; }
|
||||
|
||||
internal DataModelConditionPredicateEntity Entity { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic)
|
||||
return $"[Dynamic] {LeftPath} {Operator.Description} {RightPath}";
|
||||
return $"[Static] {LeftPath} {Operator.Description} {RightStaticValue}";
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
LeftPath?.Dispose();
|
||||
RightPath?.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
InitializeLeftPath();
|
||||
|
||||
// Operator
|
||||
if (Entity.OperatorPluginGuid != null)
|
||||
{
|
||||
BaseConditionOperator? conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
|
||||
if (conditionOperator != null)
|
||||
UpdateOperator(conditionOperator);
|
||||
}
|
||||
|
||||
// Right side dynamic
|
||||
if (PredicateType == ProfileRightSideType.Dynamic)
|
||||
InitializeRightPath();
|
||||
// Right side static
|
||||
else if (PredicateType == ProfileRightSideType.Static && Entity.RightStaticValue != null)
|
||||
try
|
||||
{
|
||||
if (LeftPath != null && LeftPath.IsValid)
|
||||
{
|
||||
// Use the left side type so JSON.NET has a better idea what to do
|
||||
Type leftSideType = LeftPath.GetPropertyType()!;
|
||||
object? rightSideValue;
|
||||
|
||||
try
|
||||
{
|
||||
rightSideValue = JsonConvert.DeserializeObject(Entity.RightStaticValue, leftSideType);
|
||||
}
|
||||
// If deserialization fails, use the type's default
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
DeserializationLogger.LogPredicateDeserializationFailure(this, e);
|
||||
rightSideValue = Activator.CreateInstance(leftSideType);
|
||||
}
|
||||
|
||||
UpdateRightSideStatic(rightSideValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hope for the best...
|
||||
UpdateRightSideStatic(JsonConvert.DeserializeObject(Entity.RightStaticValue));
|
||||
}
|
||||
}
|
||||
catch (JsonReaderException e)
|
||||
{
|
||||
DeserializationLogger.LogPredicateDeserializationFailure(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void InitializeLeftPath();
|
||||
protected abstract void InitializeRightPath();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modification
|
||||
|
||||
/// <summary>
|
||||
/// Updates the left side of the predicate
|
||||
/// </summary>
|
||||
/// <param name="path">The path pointing to the left side value inside the data model</param>
|
||||
public void UpdateLeftSide(DataModelPath? path)
|
||||
public virtual void UpdateLeftSide(DataModelPath? path)
|
||||
{
|
||||
if (path != null && !path.IsValid)
|
||||
throw new ArtemisCoreException("Cannot update left side of predicate to an invalid path");
|
||||
@ -161,153 +244,10 @@ namespace Artemis.Core
|
||||
ValidateRightSide();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Evaluate()
|
||||
{
|
||||
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
|
||||
return false;
|
||||
|
||||
// Compare with a static value
|
||||
if (PredicateType == ProfileRightSideType.Static)
|
||||
{
|
||||
object? leftSideValue = LeftPath.GetValue();
|
||||
if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null)
|
||||
return false;
|
||||
|
||||
return Operator.InternalEvaluate(leftSideValue, RightStaticValue);
|
||||
}
|
||||
|
||||
if (RightPath == null || !RightPath.IsValid)
|
||||
return false;
|
||||
|
||||
// Compare with dynamic values
|
||||
return Operator.InternalEvaluate(LeftPath.GetValue(), RightPath.GetValue());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the best type to use for the right side op this predicate
|
||||
/// </summary>
|
||||
public Type? GetPreferredRightSideType()
|
||||
{
|
||||
Type? preferredType = Operator?.RightSideType;
|
||||
Type? leftSideType = LeftPath?.GetPropertyType();
|
||||
if (preferredType == null)
|
||||
return null;
|
||||
|
||||
if (leftSideType != null && preferredType.IsAssignableFrom(leftSideType))
|
||||
preferredType = leftSideType;
|
||||
|
||||
return preferredType;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic)
|
||||
return $"[Dynamic] {LeftPath} {Operator.Description} {RightPath}";
|
||||
return $"[Static] {LeftPath} {Operator.Description} {RightStaticValue}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
LeftPath?.Dispose();
|
||||
RightPath?.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override bool EvaluateObject(object target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
// Don't save an invalid state
|
||||
if (LeftPath != null && !LeftPath.IsValid || RightPath != null && !RightPath.IsValid)
|
||||
return;
|
||||
|
||||
Entity.PredicateType = (int) PredicateType;
|
||||
|
||||
LeftPath?.Save();
|
||||
Entity.LeftPath = LeftPath?.Entity;
|
||||
RightPath?.Save();
|
||||
Entity.RightPath = RightPath?.Entity;
|
||||
|
||||
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||
|
||||
if (Operator != null)
|
||||
{
|
||||
Entity.OperatorPluginGuid = Operator.PluginInfo.Guid;
|
||||
Entity.OperatorType = Operator.GetType().Name;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
// Left side
|
||||
if (Entity.LeftPath != null)
|
||||
LeftPath = new DataModelPath(null, Entity.LeftPath);
|
||||
|
||||
// Operator
|
||||
if (Entity.OperatorPluginGuid != null)
|
||||
{
|
||||
BaseConditionOperator? conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
|
||||
if (conditionOperator != null)
|
||||
UpdateOperator(conditionOperator);
|
||||
}
|
||||
|
||||
// Right side dynamic
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
RightPath = new DataModelPath(null, Entity.RightPath);
|
||||
// Right side static
|
||||
else if (PredicateType == ProfileRightSideType.Static && Entity.RightStaticValue != null)
|
||||
try
|
||||
{
|
||||
if (LeftPath != null && LeftPath.IsValid)
|
||||
{
|
||||
// Use the left side type so JSON.NET has a better idea what to do
|
||||
Type leftSideType = LeftPath.GetPropertyType()!;
|
||||
object? rightSideValue;
|
||||
|
||||
try
|
||||
{
|
||||
rightSideValue = JsonConvert.DeserializeObject(Entity.RightStaticValue, leftSideType);
|
||||
}
|
||||
// If deserialization fails, use the type's default
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
DeserializationLogger.LogPredicateDeserializationFailure(this, e);
|
||||
rightSideValue = Activator.CreateInstance(leftSideType);
|
||||
}
|
||||
|
||||
UpdateRightSideStatic(rightSideValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hope for the best...
|
||||
UpdateRightSideStatic(JsonConvert.DeserializeObject(Entity.RightStaticValue));
|
||||
}
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
// ignored
|
||||
// TODO: Some logging would be nice
|
||||
}
|
||||
}
|
||||
|
||||
internal override DataModelConditionPartEntity GetEntity()
|
||||
{
|
||||
return Entity;
|
||||
}
|
||||
public abstract Type? GetPreferredRightSideType();
|
||||
|
||||
private void ValidateOperator()
|
||||
{
|
||||
@ -343,6 +283,72 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Evaluation
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Evaluate()
|
||||
{
|
||||
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
|
||||
return false;
|
||||
|
||||
// Compare with a static value
|
||||
if (PredicateType == ProfileRightSideType.Static)
|
||||
{
|
||||
object? leftSideValue = LeftPath.GetValue();
|
||||
if (leftSideValue != null && leftSideValue.GetType().IsValueType && RightStaticValue == null)
|
||||
return false;
|
||||
|
||||
return Operator.InternalEvaluate(leftSideValue, RightStaticValue);
|
||||
}
|
||||
|
||||
if (RightPath == null || !RightPath.IsValid)
|
||||
return false;
|
||||
|
||||
// Compare with dynamic values
|
||||
return Operator.InternalEvaluate(LeftPath.GetValue(), RightPath.GetValue());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override bool EvaluateObject(object target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Storage
|
||||
|
||||
internal override DataModelConditionPartEntity GetEntity()
|
||||
{
|
||||
return Entity;
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
// Don't save an invalid state
|
||||
if (LeftPath != null && !LeftPath.IsValid || RightPath != null && !RightPath.IsValid)
|
||||
return;
|
||||
|
||||
Entity.PredicateType = (int) PredicateType;
|
||||
|
||||
LeftPath?.Save();
|
||||
Entity.LeftPath = LeftPath?.Entity;
|
||||
RightPath?.Save();
|
||||
Entity.RightPath = RightPath?.Entity;
|
||||
|
||||
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||
|
||||
if (Operator != null)
|
||||
{
|
||||
Entity.OperatorPluginGuid = Operator.PluginInfo.Guid;
|
||||
Entity.OperatorType = Operator.GetType().Name;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ConditionOperatorStoreOnConditionOperatorAdded(object? sender, ConditionOperatorStoreEvent e)
|
||||
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile.Conditions;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A predicate in a data model condition using either two data model values or one data model value and a
|
||||
/// static value
|
||||
/// </summary>
|
||||
public class DataModelConditionGeneralPredicate : DataModelConditionPredicate
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModelConditionGeneralPredicate" /> class
|
||||
/// </summary>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="predicateType"></param>
|
||||
public DataModelConditionGeneralPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
|
||||
: base(parent, predicateType, new DataModelConditionGeneralPredicateEntity())
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal DataModelConditionGeneralPredicate(DataModelConditionPart parent, DataModelConditionGeneralPredicateEntity entity)
|
||||
: base(parent, entity)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region Modification
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type? GetPreferredRightSideType()
|
||||
{
|
||||
Type? preferredType = Operator?.RightSideType;
|
||||
Type? leftSideType = LeftPath?.GetPropertyType();
|
||||
if (preferredType == null)
|
||||
return null;
|
||||
|
||||
if (leftSideType != null && preferredType.IsAssignableFrom(leftSideType))
|
||||
preferredType = leftSideType;
|
||||
|
||||
return preferredType;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
|
||||
protected override void InitializeLeftPath()
|
||||
{
|
||||
if (Entity.LeftPath != null)
|
||||
LeftPath = new DataModelPath(null, Entity.LeftPath);
|
||||
}
|
||||
|
||||
protected override void InitializeRightPath()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
RightPath = new DataModelPath(null, Entity.RightPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -42,8 +42,8 @@ namespace Artemis.Core
|
||||
AddChild(new DataModelConditionList(this, listEntity));
|
||||
else if (childEntity is DataModelConditionEventEntity eventEntity)
|
||||
AddChild(new DataModelConditionEvent(this, eventEntity));
|
||||
else if (childEntity is DataModelConditionPredicateEntity predicateEntity)
|
||||
AddChild(new DataModelConditionPredicate(this, predicateEntity));
|
||||
else if (childEntity is DataModelConditionGeneralPredicateEntity predicateEntity)
|
||||
AddChild(new DataModelConditionGeneralPredicate(this, predicateEntity));
|
||||
else if (childEntity is DataModelConditionListPredicateEntity listPredicateEntity)
|
||||
AddChild(new DataModelConditionListPredicate(this, listPredicateEntity));
|
||||
}
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.DataModelExpansions;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using Artemis.Storage.Entities.Profile.Conditions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A predicate like evaluated inside a <see cref="DataModelConditionList" />
|
||||
/// </summary>
|
||||
public class DataModelConditionListPredicate : DataModelConditionPart
|
||||
public class DataModelConditionListPredicate : DataModelConditionPredicate
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DataModelConditionListPredicate" /> class
|
||||
@ -18,173 +14,97 @@ namespace Artemis.Core
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="predicateType"></param>
|
||||
public DataModelConditionListPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
|
||||
: base(parent, predicateType, new DataModelConditionListPredicateEntity())
|
||||
{
|
||||
Parent = parent;
|
||||
PredicateType = predicateType;
|
||||
Entity = new DataModelConditionListPredicateEntity();
|
||||
|
||||
DataModelConditionList = null!;
|
||||
ApplyParentList();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal DataModelConditionListPredicate(DataModelConditionPart parent, DataModelConditionListPredicateEntity entity)
|
||||
: base(parent, entity)
|
||||
{
|
||||
Parent = parent;
|
||||
Entity = entity;
|
||||
PredicateType = (ProfileRightSideType) entity.PredicateType;
|
||||
|
||||
DataModelConditionList = null!;
|
||||
ApplyParentList();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the predicate type
|
||||
/// </summary>
|
||||
public ProfileRightSideType PredicateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the operator
|
||||
/// </summary>
|
||||
public BaseConditionOperator? Operator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data model condition list this predicate belongs to
|
||||
/// </summary>
|
||||
public DataModelConditionList DataModelConditionList { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the left property
|
||||
/// </summary>
|
||||
public DataModelPath? LeftPath { get; private set; }
|
||||
private void ApplyParentList()
|
||||
{
|
||||
DataModelConditionPart? current = Parent;
|
||||
while (current != null)
|
||||
{
|
||||
if (current is DataModelConditionList parentList)
|
||||
{
|
||||
DataModelConditionList = parentList;
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the right property
|
||||
/// </summary>
|
||||
public DataModelPath? RightPath { get; private set; }
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right static value, only used it <see cref="PredicateType" /> is
|
||||
/// <see cref="ProfileRightSideType.Static" />
|
||||
/// </summary>
|
||||
public object? RightStaticValue { get; private set; }
|
||||
if (DataModelConditionList == null)
|
||||
throw new ArtemisCoreException("This data model condition list predicate does not belong to a data model condition list");
|
||||
}
|
||||
|
||||
internal DataModelConditionListPredicateEntity Entity { get; set; }
|
||||
private object? GetListPathValue(DataModelPath path, object target)
|
||||
{
|
||||
if (!(path.Target is ListPredicateWrapperDataModel wrapper))
|
||||
throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target");
|
||||
|
||||
wrapper.UntypedValue = target;
|
||||
return path.GetValue();
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
|
||||
protected override void InitializeLeftPath()
|
||||
{
|
||||
if (Entity.LeftPath != null)
|
||||
LeftPath = DataModelConditionList.ListType != null
|
||||
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.LeftPath)
|
||||
: null;
|
||||
}
|
||||
|
||||
protected override void InitializeRightPath()
|
||||
{
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
{
|
||||
// Right side dynamic inside the list
|
||||
// TODO: Come up with a general wrapper solution because this will clash with events
|
||||
if (Entity.RightPath.DataModelGuid == Constants.CorePluginInfo.Guid)
|
||||
RightPath = DataModelConditionList.ListType != null
|
||||
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
|
||||
: null;
|
||||
// Right side dynamic
|
||||
else
|
||||
RightPath = new DataModelPath(null, Entity.RightPath);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modification
|
||||
|
||||
/// <summary>
|
||||
/// Updates the left side of the predicate
|
||||
/// </summary>
|
||||
/// <param name="path">The path pointing to the left side value inside the list</param>
|
||||
public void UpdateLeftSide(DataModelPath? path)
|
||||
public override void UpdateLeftSide(DataModelPath? path)
|
||||
{
|
||||
if (DataModelConditionList.IsPrimitiveList)
|
||||
throw new ArtemisCoreException("Cannot apply a left side to a predicate inside a primitive list");
|
||||
|
||||
if (path != null && !path.IsValid)
|
||||
throw new ArtemisCoreException("Cannot update left side of predicate to an invalid path");
|
||||
|
||||
LeftPath?.Dispose();
|
||||
LeftPath = path != null ? new DataModelPath(path) : null;
|
||||
|
||||
ValidateOperator();
|
||||
ValidateRightSide();
|
||||
base.UpdateLeftSide(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the right side of the predicate using a path and makes the predicate dynamic
|
||||
/// </summary>
|
||||
/// <param name="path">The path pointing to the right side value</param>
|
||||
public void UpdateRightSideDynamic(DataModelPath? path)
|
||||
{
|
||||
if (path != null && !path.IsValid)
|
||||
throw new ArtemisCoreException("Cannot update right side of predicate to an invalid path");
|
||||
if (Operator != null && path != null && !Operator.SupportsType(path.GetPropertyType()!, ConditionParameterSide.Right))
|
||||
throw new ArtemisCoreException($"Selected operator does not support right side of type {path.GetPropertyType()!.Name}");
|
||||
|
||||
RightPath?.Dispose();
|
||||
RightPath = path != null ? new DataModelPath(path) : null;
|
||||
|
||||
PredicateType = ProfileRightSideType.Dynamic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the right side of the predicate, makes the predicate static and re-compiles the expression
|
||||
/// </summary>
|
||||
/// <param name="staticValue">The right side value to use</param>
|
||||
public void UpdateRightSideStatic(object? staticValue)
|
||||
{
|
||||
PredicateType = ProfileRightSideType.Static;
|
||||
RightPath?.Dispose();
|
||||
RightPath = null;
|
||||
|
||||
SetStaticValue(staticValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the operator of the predicate and re-compiles the expression
|
||||
/// </summary>
|
||||
/// <param name="conditionOperator"></param>
|
||||
public void UpdateOperator(BaseConditionOperator? conditionOperator)
|
||||
{
|
||||
if (conditionOperator == null)
|
||||
{
|
||||
Operator = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to clear compiled expressions, without a left data model they are already null
|
||||
if (LeftPath == null || !LeftPath.IsValid)
|
||||
{
|
||||
Operator = conditionOperator;
|
||||
return;
|
||||
}
|
||||
|
||||
Type leftType = LeftPath.GetPropertyType()!;
|
||||
// Left side can't go empty so enforce a match
|
||||
if (!conditionOperator.SupportsType(leftType, ConditionParameterSide.Left))
|
||||
throw new ArtemisCoreException($"Cannot apply operator {conditionOperator.GetType().Name} to this predicate because " +
|
||||
$"it does not support left side type {leftType.Name}");
|
||||
|
||||
Operator = conditionOperator;
|
||||
ValidateRightSide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported for list predicates, always returns <c>false</c>
|
||||
/// </summary>
|
||||
public override bool Evaluate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the provided path is contained inside the list
|
||||
/// </summary>
|
||||
/// <param name="path">The path to evaluate</param>
|
||||
public bool ListContainsInnerPath(string path)
|
||||
{
|
||||
if (DataModelConditionList.ListType == null)
|
||||
return false;
|
||||
|
||||
string[] parts = path.Split('.');
|
||||
Type current = DataModelConditionList.ListType;
|
||||
foreach (string part in parts)
|
||||
{
|
||||
PropertyInfo? property = current.GetProperty(part);
|
||||
current = property?.PropertyType;
|
||||
|
||||
if (property == null)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the best type to use for the right side op this predicate
|
||||
/// </summary>
|
||||
public Type? GetPreferredRightSideType()
|
||||
/// <inheritdoc />
|
||||
public override Type? GetPreferredRightSideType()
|
||||
{
|
||||
Type? preferredType = Operator?.RightSideType;
|
||||
Type? leftSideType = DataModelConditionList.IsPrimitiveList
|
||||
@ -199,22 +119,18 @@ namespace Artemis.Core
|
||||
return preferredType;
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
LeftPath?.Dispose();
|
||||
RightPath?.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Evaluation
|
||||
|
||||
/// <summary>
|
||||
/// Not supported for list predicates, always returns <c>false</c>
|
||||
/// </summary>
|
||||
public override bool Evaluate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool EvaluateObject(object target)
|
||||
{
|
||||
if (Operator == null || LeftPath == null || !LeftPath.IsValid)
|
||||
@ -245,227 +161,6 @@ namespace Artemis.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
internal Type GetTypeAtInnerPath(string path)
|
||||
{
|
||||
if (!ListContainsInnerPath(path))
|
||||
return null;
|
||||
|
||||
string[] parts = path.Split('.');
|
||||
Type current = DataModelConditionList.ListType;
|
||||
|
||||
Type result = null;
|
||||
foreach (string part in parts)
|
||||
{
|
||||
PropertyInfo? property = current.GetProperty(part);
|
||||
current = property.PropertyType;
|
||||
result = property.PropertyType;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
Entity.PredicateType = (int) PredicateType;
|
||||
|
||||
LeftPath?.Save();
|
||||
Entity.LeftPath = LeftPath?.Entity;
|
||||
RightPath?.Save();
|
||||
Entity.RightPath = RightPath?.Entity;
|
||||
|
||||
Entity.RightStaticValue = JsonConvert.SerializeObject(RightStaticValue);
|
||||
|
||||
if (Operator != null)
|
||||
{
|
||||
Entity.OperatorPluginGuid = Operator.PluginInfo.Guid;
|
||||
Entity.OperatorType = Operator.GetType().Name;
|
||||
}
|
||||
}
|
||||
|
||||
internal override DataModelConditionPartEntity GetEntity()
|
||||
{
|
||||
return Entity;
|
||||
}
|
||||
|
||||
private void ApplyParentList()
|
||||
{
|
||||
DataModelConditionPart? current = Parent;
|
||||
while (current != null)
|
||||
{
|
||||
if (current is DataModelConditionList parentList)
|
||||
{
|
||||
DataModelConditionList = parentList;
|
||||
return;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
if (DataModelConditionList == null)
|
||||
throw new ArtemisCoreException("This data model condition list predicate does not belong to a data model condition list");
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
ConditionOperatorStore.ConditionOperatorAdded += ConditionOperatorStoreOnConditionOperatorAdded;
|
||||
ConditionOperatorStore.ConditionOperatorRemoved += ConditionOperatorStoreOnConditionOperatorRemoved;
|
||||
|
||||
// Left side
|
||||
if (Entity.LeftPath != null)
|
||||
{
|
||||
LeftPath = DataModelConditionList.ListType != null
|
||||
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.LeftPath)
|
||||
: null;
|
||||
}
|
||||
|
||||
// Operator
|
||||
if (Entity.OperatorPluginGuid != null)
|
||||
{
|
||||
BaseConditionOperator? conditionOperator = ConditionOperatorStore.Get(Entity.OperatorPluginGuid.Value, Entity.OperatorType)?.ConditionOperator;
|
||||
if (conditionOperator != null)
|
||||
UpdateOperator(conditionOperator);
|
||||
}
|
||||
|
||||
// Right side dynamic
|
||||
if (PredicateType == ProfileRightSideType.Dynamic && Entity.RightPath != null)
|
||||
{
|
||||
// Right side dynamic inside the list
|
||||
// TODO: Come up with a general wrapper solution because this will clash with events
|
||||
if (Entity.RightPath.DataModelGuid == Constants.CorePluginInfo.Guid)
|
||||
{
|
||||
RightPath = DataModelConditionList.ListType != null
|
||||
? new DataModelPath(ListPredicateWrapperDataModel.Create(DataModelConditionList.ListType), Entity.RightPath)
|
||||
: null;
|
||||
}
|
||||
// Right side dynamic
|
||||
else
|
||||
RightPath = new DataModelPath(null, Entity.RightPath);
|
||||
}
|
||||
// Right side static
|
||||
else if (PredicateType == ProfileRightSideType.Static && Entity.RightStaticValue != null)
|
||||
try
|
||||
{
|
||||
if (LeftPath != null && LeftPath.IsValid)
|
||||
{
|
||||
// Use the left side type so JSON.NET has a better idea what to do
|
||||
Type leftSideType = LeftPath.GetPropertyType()!;
|
||||
object? rightSideValue;
|
||||
|
||||
try
|
||||
{
|
||||
rightSideValue = JsonConvert.DeserializeObject(Entity.RightStaticValue, leftSideType);
|
||||
}
|
||||
// If deserialization fails, use the type's default
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
DeserializationLogger.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)
|
||||
{
|
||||
DeserializationLogger.LogListPredicateDeserializationFailure(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateOperator()
|
||||
{
|
||||
if (LeftPath == null || !LeftPath.IsValid || Operator == null)
|
||||
return;
|
||||
|
||||
Type leftType = LeftPath.GetPropertyType()!;
|
||||
if (!Operator.SupportsType(leftType, ConditionParameterSide.Left))
|
||||
Operator = null;
|
||||
}
|
||||
|
||||
private void ValidateRightSide()
|
||||
{
|
||||
if (Operator == null)
|
||||
return;
|
||||
|
||||
if (PredicateType == ProfileRightSideType.Dynamic)
|
||||
{
|
||||
if (RightPath == null || !RightPath.IsValid)
|
||||
return;
|
||||
|
||||
Type rightSideType = RightPath.GetPropertyType()!;
|
||||
if (!Operator.SupportsType(rightSideType, ConditionParameterSide.Right))
|
||||
UpdateRightSideDynamic(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RightStaticValue == null)
|
||||
return;
|
||||
|
||||
if (!Operator.SupportsType(RightStaticValue.GetType(), ConditionParameterSide.Right))
|
||||
UpdateRightSideStatic(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetStaticValue(object? staticValue)
|
||||
{
|
||||
RightPath?.Dispose();
|
||||
RightPath = null;
|
||||
|
||||
// If the operator is null simply apply the value, any validation will wait
|
||||
if (Operator == null)
|
||||
{
|
||||
RightStaticValue = staticValue;
|
||||
return;
|
||||
}
|
||||
// If the operator does not support a right side, always set it to null
|
||||
if (Operator.RightSideType == null)
|
||||
{
|
||||
RightStaticValue = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// If not null ensure the types match and if not, convert it
|
||||
Type? preferredType = GetPreferredRightSideType();
|
||||
if (staticValue != null && staticValue.GetType() == preferredType || preferredType == null)
|
||||
RightStaticValue = staticValue;
|
||||
else if (staticValue != null)
|
||||
RightStaticValue = Convert.ChangeType(staticValue, preferredType);
|
||||
// If null create a default instance for value types or simply make it null for reference types
|
||||
else if (preferredType.IsValueType)
|
||||
RightStaticValue = Activator.CreateInstance(preferredType);
|
||||
else
|
||||
RightStaticValue = null;
|
||||
}
|
||||
|
||||
private object? GetListPathValue(DataModelPath path, object target)
|
||||
{
|
||||
if (!(path.Target is ListPredicateWrapperDataModel wrapper))
|
||||
throw new ArtemisCoreException("Data model condition list predicate has a path with an invalid target");
|
||||
|
||||
wrapper.UntypedValue = target;
|
||||
return path.GetValue();
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void ConditionOperatorStoreOnConditionOperatorAdded(object sender, ConditionOperatorStoreEvent e)
|
||||
{
|
||||
BaseConditionOperator conditionOperator = e.Registration.ConditionOperator;
|
||||
if (Entity.OperatorPluginGuid == conditionOperator.PluginInfo.Guid && Entity.OperatorType == conditionOperator.GetType().Name)
|
||||
UpdateOperator(conditionOperator);
|
||||
}
|
||||
|
||||
private void ConditionOperatorStoreOnConditionOperatorRemoved(object sender, ConditionOperatorStoreEvent e)
|
||||
{
|
||||
if (e.Registration.ConditionOperator != Operator)
|
||||
return;
|
||||
Operator = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -24,17 +24,6 @@ namespace Artemis.Core
|
||||
);
|
||||
}
|
||||
|
||||
public static void LogListPredicateDeserializationFailure(DataModelConditionListPredicate dataModelConditionPredicate, JsonException exception)
|
||||
{
|
||||
_logger.Warning(
|
||||
exception,
|
||||
"Failed to deserialize display condition list predicate {list} => {left} {operator} {right}",
|
||||
dataModelConditionPredicate.Entity.LeftPath?.Path,
|
||||
dataModelConditionPredicate.Entity.OperatorType,
|
||||
dataModelConditionPredicate.Entity.RightPath?.Path
|
||||
);
|
||||
}
|
||||
|
||||
public static void LogModifierDeserializationFailure(string modifierName, JsonSerializationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Failed to deserialize static parameter for modifier {modifierName}", modifierName);
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions
|
||||
{
|
||||
public class DataModelConditionGeneralPredicateEntity : DataModelConditionPredicateEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,6 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions
|
||||
{
|
||||
public class DataModelConditionListPredicateEntity : DataModelConditionPartEntity
|
||||
public class DataModelConditionListPredicateEntity : DataModelConditionPredicateEntity
|
||||
{
|
||||
public int PredicateType { get; set; }
|
||||
|
||||
public DataModelPathEntity LeftPath { get; set; }
|
||||
public DataModelPathEntity RightPath { 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; }
|
||||
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ using Artemis.Storage.Entities.Profile.Abstract;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile.Conditions
|
||||
{
|
||||
public class DataModelConditionPredicateEntity : DataModelConditionPartEntity
|
||||
public abstract class DataModelConditionPredicateEntity : DataModelConditionPartEntity
|
||||
{
|
||||
public int PredicateType { get; set; }
|
||||
public DataModelPathEntity LeftPath { get; set; }
|
||||
@ -14,6 +14,5 @@ namespace Artemis.Storage.Entities.Profile.Conditions
|
||||
|
||||
// Stored as a string to be able to control serialization and deserialization ourselves
|
||||
public string RightStaticValue { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
34
src/Artemis.Storage/Migrations/M6PredicateAbstraction.cs
Normal file
34
src/Artemis.Storage/Migrations/M6PredicateAbstraction.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Migrations
|
||||
{
|
||||
public class M6PredicateAbstraction : IStorageMigration
|
||||
{
|
||||
public int UserVersion => 7;
|
||||
|
||||
public void Apply(LiteRepository repository)
|
||||
{
|
||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||
foreach (BsonDocument bsonDocument in collection.FindAll())
|
||||
{
|
||||
|
||||
foreach (BsonValue bsonLayer in bsonDocument["Layers"].AsArray)
|
||||
{
|
||||
bsonLayer["DisplayCondition"] = null;
|
||||
foreach (BsonValue bsonPropertyEntity in bsonLayer["PropertyEntities"].AsArray)
|
||||
bsonPropertyEntity["DataBindingEntities"].AsArray.Clear();
|
||||
}
|
||||
|
||||
foreach (BsonValue bsonLayer in bsonDocument["Folders"].AsArray)
|
||||
{
|
||||
bsonLayer["DisplayCondition"] = null;
|
||||
foreach (BsonValue bsonPropertyEntity in bsonLayer["PropertyEntities"].AsArray)
|
||||
bsonPropertyEntity["DataBindingEntities"].AsArray.Clear();
|
||||
}
|
||||
|
||||
collection.Update(bsonDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
src/Artemis.UI/Artemis.UI.csproj.DotSettings
Normal file
2
src/Artemis.UI/Artemis.UI.csproj.DotSettings
Normal file
@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=screens_005Cprofileeditor_005Cconditions_005Cpredicate/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@ -68,7 +68,7 @@ namespace Artemis.UI.Ninject.Factories
|
||||
DataModelConditionGroupViewModel DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup, bool isListGroup);
|
||||
DataModelConditionListViewModel DataModelConditionListViewModel(DataModelConditionList dataModelConditionList);
|
||||
DataModelConditionEventViewModel DataModelConditionEventViewModel(DataModelConditionEvent dataModelConditionEvent);
|
||||
DataModelConditionPredicateViewModel DataModelConditionPredicateViewModel(DataModelConditionPredicate dataModelConditionPredicate);
|
||||
DataModelConditionGeneralPredicateViewModel DataModelConditionGeneralPredicateViewModel(DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate);
|
||||
DataModelConditionListPredicateViewModel DataModelConditionListPredicateViewModel(DataModelConditionListPredicate dataModelConditionListPredicate);
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionPredicateViewModel : DataModelConditionViewModel, IDisposable
|
||||
public abstract class DataModelConditionPredicateViewModel : DataModelConditionViewModel, IDisposable
|
||||
{
|
||||
private readonly IConditionOperatorService _conditionOperatorService;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
@ -41,20 +41,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
Operators = new BindableCollection<BaseConditionOperator>();
|
||||
|
||||
ShowDataModelValues = settingsService.GetSetting<bool>("ProfileEditor.ShowDataModelValues");
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public DataModelConditionPredicate DataModelConditionPredicate => (DataModelConditionPredicate) Model;
|
||||
public PluginSetting<bool> ShowDataModelValues { get; }
|
||||
|
||||
|
||||
public BindableCollection<BaseConditionOperator> Operators
|
||||
{
|
||||
get => _operators;
|
||||
set => SetAndNotify(ref _operators, value);
|
||||
}
|
||||
|
||||
public BaseConditionOperator SelectedOperator
|
||||
{
|
||||
get => _selectedOperator;
|
||||
@ -74,6 +65,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
}
|
||||
|
||||
public DelegateCommand SelectOperatorCommand { get; }
|
||||
public BindableCollection<BaseConditionOperator> Operators { get; }
|
||||
|
||||
protected SolidColorBrush LeftSideColor { get; set; }
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
@ -81,17 +75,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
public virtual void Initialize()
|
||||
{
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
LeftSideSelectionViewModel.PropertySelected += LeftSideOnPropertySelected;
|
||||
if (LeftSideColor != null)
|
||||
LeftSideSelectionViewModel.ButtonBrush = LeftSideColor;
|
||||
|
||||
// Determine which types are currently supported
|
||||
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
|
||||
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||
_supportedInputTypes.Add(typeof(IEnumerable<>));
|
||||
_supportedInputTypes.Add(typeof(DataModelEvent));
|
||||
_supportedInputTypes.Add(typeof(DataModelEvent<>));
|
||||
_supportedInputTypes = GetSupportedInputTypes();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
@ -100,7 +93,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
|
||||
LeftSideSelectionViewModel.ChangeDataModelPath(DataModelConditionPredicate.LeftPath);
|
||||
|
||||
Type leftSideType = LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
|
||||
Type leftSideType = GetLeftSideType();
|
||||
|
||||
// Get the supported operators
|
||||
Operators.Clear();
|
||||
@ -139,7 +132,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
RightSideInputViewModel.Value = preferredType.GetDefault();
|
||||
else
|
||||
RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue;
|
||||
|
||||
|
||||
if (RightSideInputViewModel.TargetType != preferredType)
|
||||
RightSideInputViewModel.UpdateTargetType(preferredType);
|
||||
}
|
||||
@ -183,15 +176,23 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
Update();
|
||||
}
|
||||
|
||||
protected abstract List<Type> GetSupportedInputTypes();
|
||||
protected abstract Type GetLeftSideType();
|
||||
|
||||
protected virtual List<DataModelPropertiesViewModel> GetExtraRightSideDataModelViewModels()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ExecuteSelectOperatorCommand(object context)
|
||||
{
|
||||
if (!(context is BaseConditionOperator DataModelConditionOperator))
|
||||
if (!(context is BaseConditionOperator dataModelConditionOperator))
|
||||
return;
|
||||
|
||||
SelectedOperator = DataModelConditionOperator;
|
||||
SelectedOperator = dataModelConditionOperator;
|
||||
ApplyOperator();
|
||||
}
|
||||
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
@ -218,6 +219,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
RightSideSelectionViewModel.DisplaySwitchButton = true;
|
||||
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
|
||||
RightSideSelectionViewModel.SwitchToStaticRequested += RightSideSelectionViewModelOnSwitchToStaticRequested;
|
||||
|
||||
List<DataModelPropertiesViewModel> extra = GetExtraRightSideDataModelViewModels();
|
||||
if (extra != null)
|
||||
RightSideSelectionViewModel.ExtraDataModelViewModels.AddRange(extra);
|
||||
}
|
||||
|
||||
private void CreateRightSideInputViewModel()
|
||||
@ -69,7 +69,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
public void AddCondition()
|
||||
{
|
||||
if (!IsListGroup)
|
||||
DataModelConditionGroup.AddChild(new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
|
||||
DataModelConditionGroup.AddChild(new DataModelConditionGeneralPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
|
||||
else
|
||||
DataModelConditionGroup.AddChild(new DataModelConditionListPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic));
|
||||
|
||||
@ -109,9 +109,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
case DataModelConditionEvent dataModelConditionEvent:
|
||||
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionEventViewModel(dataModelConditionEvent));
|
||||
break;
|
||||
case DataModelConditionPredicate dataModelConditionPredicate:
|
||||
case DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate:
|
||||
if (!IsListGroup)
|
||||
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionPredicateViewModel(dataModelConditionPredicate));
|
||||
viewModels.Add(_dataModelConditionsVmFactory.DataModelConditionGeneralPredicateViewModel(dataModelConditionGeneralPredicate));
|
||||
break;
|
||||
case DataModelConditionListPredicate dataModelConditionListPredicate:
|
||||
if (IsListGroup)
|
||||
@ -175,7 +175,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
DataModelConditionGroup.RemoveChild(listViewModel.Model);
|
||||
|
||||
// Insert a list in the same position
|
||||
DataModelConditionPredicate predicate = new DataModelConditionPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic);
|
||||
DataModelConditionGeneralPredicate predicate = new DataModelConditionGeneralPredicate(DataModelConditionGroup, ProfileRightSideType.Dynamic);
|
||||
predicate.UpdateLeftSide(listViewModel.LeftSideSelectionViewModel.DataModelPath);
|
||||
DataModelConditionGroup.AddChild(predicate, index);
|
||||
|
||||
|
||||
@ -1,323 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Screens.ProfileEditor.Conditions.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Input;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionListPredicateViewModel : DataModelConditionViewModel, IDisposable
|
||||
{
|
||||
private readonly IConditionOperatorService _conditionOperatorService;
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _isPrimitiveList;
|
||||
private DataModelDynamicViewModel _leftSideSelectionViewModel;
|
||||
private BindableCollection<BaseConditionOperator> _operators;
|
||||
private DataModelStaticViewModel _rightSideInputViewModel;
|
||||
private DataModelDynamicViewModel _rightSideSelectionViewModel;
|
||||
private BaseConditionOperator _selectedOperator;
|
||||
|
||||
private List<Type> _supportedInputTypes;
|
||||
|
||||
public DataModelConditionListPredicateViewModel(
|
||||
DataModelConditionListPredicate dataModelConditionListPredicate,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService) : base(dataModelConditionListPredicate)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_conditionOperatorService = conditionOperatorService;
|
||||
_supportedInputTypes = new List<Type>();
|
||||
|
||||
SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand);
|
||||
Operators = new BindableCollection<BaseConditionOperator>();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public DataModelConditionListPredicate DataModelConditionListPredicate => (DataModelConditionListPredicate) Model;
|
||||
|
||||
public BindableCollection<BaseConditionOperator> Operators
|
||||
{
|
||||
get => _operators;
|
||||
set => SetAndNotify(ref _operators, value);
|
||||
}
|
||||
|
||||
public DataModelDynamicViewModel LeftSideSelectionViewModel
|
||||
{
|
||||
get => _leftSideSelectionViewModel;
|
||||
set => SetAndNotify(ref _leftSideSelectionViewModel, value);
|
||||
}
|
||||
|
||||
public DataModelDynamicViewModel RightSideSelectionViewModel
|
||||
{
|
||||
get => _rightSideSelectionViewModel;
|
||||
set => SetAndNotify(ref _rightSideSelectionViewModel, value);
|
||||
}
|
||||
|
||||
public DataModelStaticViewModel RightSideInputViewModel
|
||||
{
|
||||
get => _rightSideInputViewModel;
|
||||
set => SetAndNotify(ref _rightSideInputViewModel, value);
|
||||
}
|
||||
|
||||
public BaseConditionOperator SelectedOperator
|
||||
{
|
||||
get => _selectedOperator;
|
||||
set => SetAndNotify(ref _selectedOperator, value);
|
||||
}
|
||||
|
||||
public DelegateCommand SelectOperatorCommand { get; }
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
DataModelPropertiesViewModel listDataModel = GetListDataModel();
|
||||
if (listDataModel.Children.Count == 1 && listDataModel.Children.First() is DataModelListPropertyViewModel)
|
||||
_isPrimitiveList = true;
|
||||
else
|
||||
_isPrimitiveList = false;
|
||||
|
||||
// Get the data models
|
||||
if (!_isPrimitiveList)
|
||||
{
|
||||
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
LeftSideSelectionViewModel.ChangeDataModel(listDataModel);
|
||||
LeftSideSelectionViewModel.PropertySelected += LeftSideOnPropertySelected;
|
||||
}
|
||||
|
||||
// Determine which types are currently supported
|
||||
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
|
||||
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
Guid? listDataModelGuid = DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid;
|
||||
if (listDataModelGuid == null)
|
||||
return;
|
||||
|
||||
if (!_isPrimitiveList)
|
||||
{
|
||||
// Lists use a different color
|
||||
LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(71, 108, 188));
|
||||
LeftSideSelectionViewModel.FilterTypes = _supportedInputTypes.ToArray();
|
||||
LeftSideSelectionViewModel.ChangeDataModelPath(DataModelConditionListPredicate.LeftPath);
|
||||
}
|
||||
|
||||
Type leftSideType = _isPrimitiveList
|
||||
? DataModelConditionListPredicate.DataModelConditionList.ListType
|
||||
: LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
|
||||
|
||||
// Get the supported operators
|
||||
Operators.Clear();
|
||||
Operators.AddRange(_conditionOperatorService.GetConditionOperatorsForType(leftSideType ?? typeof(object), ConditionParameterSide.Left));
|
||||
if (DataModelConditionListPredicate.Operator == null)
|
||||
DataModelConditionListPredicate.UpdateOperator(Operators.FirstOrDefault(o => o.SupportsType(leftSideType ?? typeof(object), ConditionParameterSide.Left)));
|
||||
SelectedOperator = DataModelConditionListPredicate.Operator;
|
||||
|
||||
// Without a selected operator or one that supports a right side, leave the right side input empty
|
||||
if (SelectedOperator == null || SelectedOperator.RightSideType == null)
|
||||
{
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the right side has the proper VM
|
||||
if (DataModelConditionListPredicate.PredicateType == ProfileRightSideType.Dynamic)
|
||||
{
|
||||
DisposeRightSideStaticViewModel();
|
||||
if (RightSideSelectionViewModel == null)
|
||||
CreateRightSideSelectionViewModel();
|
||||
|
||||
RightSideSelectionViewModel.ChangeDataModelPath(DataModelConditionListPredicate.RightPath);
|
||||
RightSideSelectionViewModel.FilterTypes = new[] {SelectedOperator.RightSideType};
|
||||
}
|
||||
else
|
||||
{
|
||||
DisposeRightSideDynamicViewModel();
|
||||
if (RightSideInputViewModel == null)
|
||||
CreateRightSideInputViewModel();
|
||||
|
||||
Type preferredType = DataModelConditionListPredicate.GetPreferredRightSideType();
|
||||
if (preferredType.IsValueType && DataModelConditionListPredicate.RightStaticValue == null)
|
||||
RightSideInputViewModel.Value = preferredType.GetDefault();
|
||||
else
|
||||
RightSideInputViewModel.Value = DataModelConditionListPredicate.RightStaticValue;
|
||||
|
||||
if (RightSideInputViewModel.TargetType != preferredType)
|
||||
RightSideInputViewModel.UpdateTargetType(preferredType);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyLeftSide()
|
||||
{
|
||||
DataModelConditionListPredicate.UpdateLeftSide(LeftSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
SelectedOperator = DataModelConditionListPredicate.Operator;
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ApplyRightSideDynamic()
|
||||
{
|
||||
DataModelConditionListPredicate.UpdateRightSideDynamic(RightSideSelectionViewModel.DataModelPath);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ApplyRightSideStatic(object value)
|
||||
{
|
||||
DataModelConditionListPredicate.UpdateRightSideStatic(value);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void ApplyOperator()
|
||||
{
|
||||
DataModelConditionListPredicate.UpdateOperator(SelectedOperator);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private DataModelPropertiesViewModel GetListDataModel()
|
||||
{
|
||||
if (DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid == null)
|
||||
throw new ArtemisUIException("Failed to retrieve the list data model VM for this list predicate because it has no list path");
|
||||
|
||||
DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true);
|
||||
DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath(
|
||||
DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value,
|
||||
DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
|
||||
);
|
||||
|
||||
return listDataModel.GetListTypeViewModel(_dataModelUIService);
|
||||
}
|
||||
|
||||
private void ExecuteSelectOperatorCommand(object context)
|
||||
{
|
||||
if (!(context is BaseConditionOperator dataModelConditionOperator))
|
||||
return;
|
||||
|
||||
SelectedOperator = dataModelConditionOperator;
|
||||
ApplyOperator();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_isPrimitiveList)
|
||||
{
|
||||
LeftSideSelectionViewModel.PropertySelected -= LeftSideOnPropertySelected;
|
||||
LeftSideSelectionViewModel.Dispose();
|
||||
}
|
||||
|
||||
DisposeRightSideStaticViewModel();
|
||||
DisposeRightSideDynamicViewModel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void LeftSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
ApplyLeftSide();
|
||||
}
|
||||
|
||||
private void RightSideOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
|
||||
{
|
||||
ApplyRightSideDynamic();
|
||||
}
|
||||
|
||||
private void RightSideOnValueEntered(object sender, DataModelInputStaticEventArgs e)
|
||||
{
|
||||
ApplyRightSideStatic(e.Value);
|
||||
}
|
||||
|
||||
private void RightSideSelectionViewModelOnSwitchToStaticRequested(object sender, EventArgs e)
|
||||
{
|
||||
DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Static;
|
||||
Update();
|
||||
}
|
||||
|
||||
private void RightSideInputViewModelOnSwitchToDynamicRequested(object? sender, EventArgs e)
|
||||
{
|
||||
DataModelConditionListPredicate.PredicateType = ProfileRightSideType.Dynamic;
|
||||
Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region View model management
|
||||
|
||||
private void CreateRightSideSelectionViewModel()
|
||||
{
|
||||
RightSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
|
||||
RightSideSelectionViewModel.ButtonBrush = (SolidColorBrush) Application.Current.FindResource("PrimaryHueMidBrush");
|
||||
RightSideSelectionViewModel.DisplaySwitchButton = true;
|
||||
RightSideSelectionViewModel.PropertySelected += RightSideOnPropertySelected;
|
||||
RightSideSelectionViewModel.SwitchToStaticRequested += RightSideSelectionViewModelOnSwitchToStaticRequested;
|
||||
|
||||
// Add an extra data model to the selection VM to allow self-referencing the current item
|
||||
// The safe cast prevents adding this extra VM on primitive lists where they serve no purpose
|
||||
if (GetListDataModel()?.Children?.FirstOrDefault() is DataModelPropertiesViewModel listValue)
|
||||
RightSideSelectionViewModel.ExtraDataModelViewModels.Add(listValue);
|
||||
}
|
||||
|
||||
private void CreateRightSideInputViewModel()
|
||||
{
|
||||
Type preferredType = DataModelConditionListPredicate.GetPreferredRightSideType();
|
||||
RightSideInputViewModel = _dataModelUIService.GetStaticInputViewModel(preferredType, LeftSideSelectionViewModel.DataModelPath?.GetPropertyDescription());
|
||||
RightSideInputViewModel.ButtonBrush = (SolidColorBrush) Application.Current.FindResource("PrimaryHueMidBrush");
|
||||
RightSideInputViewModel.DisplaySwitchButton = true;
|
||||
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
|
||||
RightSideInputViewModel.SwitchToDynamicRequested += RightSideInputViewModelOnSwitchToDynamicRequested;
|
||||
}
|
||||
|
||||
private void DisposeRightSideStaticViewModel()
|
||||
{
|
||||
if (RightSideInputViewModel == null)
|
||||
return;
|
||||
RightSideInputViewModel.ValueUpdated -= RightSideOnValueEntered;
|
||||
RightSideInputViewModel.SwitchToDynamicRequested -= RightSideInputViewModelOnSwitchToDynamicRequested;
|
||||
RightSideInputViewModel.Dispose();
|
||||
RightSideInputViewModel = null;
|
||||
}
|
||||
|
||||
private void DisposeRightSideDynamicViewModel()
|
||||
{
|
||||
if (RightSideSelectionViewModel == null)
|
||||
return;
|
||||
RightSideSelectionViewModel.PropertySelected -= RightSideOnPropertySelected;
|
||||
RightSideSelectionViewModel.SwitchToStaticRequested -= RightSideSelectionViewModelOnSwitchToStaticRequested;
|
||||
RightSideSelectionViewModel.Dispose();
|
||||
RightSideSelectionViewModel = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -45,7 +45,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
|
||||
public void AddCondition()
|
||||
{
|
||||
DataModelConditionList.AddChild(new DataModelConditionPredicate(DataModelConditionList, ProfileRightSideType.Dynamic));
|
||||
DataModelConditionList.AddChild(new DataModelConditionGeneralPredicate(DataModelConditionList, ProfileRightSideType.Dynamic));
|
||||
|
||||
Update();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||
xmlns:conditions="clr-namespace:Artemis.UI.Screens.ProfileEditor.Conditions"
|
||||
x:Class="Artemis.UI.Screens.ProfileEditor.Conditions.DataModelConditionPredicateView"
|
||||
x:Class="Artemis.UI.Screens.ProfileEditor.Conditions.DataModelConditionGeneralPredicateView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type conditions:DataModelConditionPredicateViewModel}}">
|
||||
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=False, Type={x:Type conditions:DataModelConditionGeneralPredicateViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
@ -4,11 +4,11 @@ using System.Windows.Controls;
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for DataModelConditionPredicateView.xaml
|
||||
/// Interaction logic for DataModelConditionGeneralPredicateView.xaml
|
||||
/// </summary>
|
||||
public partial class DataModelConditionPredicateView : UserControl
|
||||
public partial class DataModelConditionGeneralPredicateView : UserControl
|
||||
{
|
||||
public DataModelConditionPredicateView()
|
||||
public DataModelConditionGeneralPredicateView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionGeneralPredicateViewModel : DataModelConditionPredicateViewModel
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
|
||||
public DataModelConditionGeneralPredicateViewModel(DataModelConditionGeneralPredicate dataModelConditionGeneralPredicate,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService)
|
||||
: base(dataModelConditionGeneralPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
protected override List<Type> GetSupportedInputTypes()
|
||||
{
|
||||
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
|
||||
List<Type> supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||
supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||
supportedInputTypes.Add(typeof(IEnumerable<>));
|
||||
supportedInputTypes.Add(typeof(DataModelEvent));
|
||||
supportedInputTypes.Add(typeof(DataModelEvent<>));
|
||||
|
||||
return supportedInputTypes;
|
||||
}
|
||||
|
||||
protected override Type GetLeftSideType()
|
||||
{
|
||||
return LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
||||
{
|
||||
public class DataModelConditionListPredicateViewModel : DataModelConditionPredicateViewModel
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private bool _isPrimitiveList;
|
||||
|
||||
public DataModelConditionListPredicateViewModel(DataModelConditionListPredicate dataModelConditionListPredicate,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDataModelUIService dataModelUIService,
|
||||
IConditionOperatorService conditionOperatorService,
|
||||
ISettingsService settingsService)
|
||||
: base(dataModelConditionListPredicate, profileEditorService, dataModelUIService, conditionOperatorService, settingsService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_dataModelUIService = dataModelUIService;
|
||||
|
||||
LeftSideColor = new SolidColorBrush(Color.FromRgb(71, 108, 188));
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public DataModelConditionListPredicate DataModelConditionListPredicate => (DataModelConditionListPredicate) Model;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
DataModelPropertiesViewModel listDataModel = GetListDataModel();
|
||||
if (listDataModel.Children.Count == 1 && listDataModel.Children.First() is DataModelListPropertyViewModel)
|
||||
_isPrimitiveList = true;
|
||||
else
|
||||
_isPrimitiveList = false;
|
||||
|
||||
// Get the data models
|
||||
if (!_isPrimitiveList)
|
||||
LeftSideSelectionViewModel.ChangeDataModel(listDataModel);
|
||||
}
|
||||
|
||||
protected override List<Type> GetSupportedInputTypes()
|
||||
{
|
||||
IReadOnlyCollection<DataModelVisualizationRegistration> editors = _dataModelUIService.RegisteredDataModelEditors;
|
||||
List<Type> supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||
supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||
|
||||
return supportedInputTypes;
|
||||
}
|
||||
|
||||
protected override Type GetLeftSideType()
|
||||
{
|
||||
return DataModelConditionListPredicate.DataModelConditionList.IsPrimitiveList
|
||||
? DataModelConditionListPredicate.DataModelConditionList.ListType
|
||||
: LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
|
||||
}
|
||||
|
||||
protected override List<DataModelPropertiesViewModel> GetExtraRightSideDataModelViewModels()
|
||||
{
|
||||
if (GetListDataModel()?.Children?.FirstOrDefault() is DataModelPropertiesViewModel listValue)
|
||||
return new List<DataModelPropertiesViewModel> {listValue};
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataModelPropertiesViewModel GetListDataModel()
|
||||
{
|
||||
if (DataModelConditionListPredicate.DataModelConditionList.ListPath?.DataModelGuid == null)
|
||||
throw new ArtemisUIException("Failed to retrieve the list data model VM for this list predicate because it has no list path");
|
||||
|
||||
DataModelPropertiesViewModel dataModel = _dataModelUIService.GetPluginDataModelVisualization(_profileEditorService.GetCurrentModule(), true);
|
||||
DataModelListViewModel listDataModel = (DataModelListViewModel) dataModel.GetChildByPath(
|
||||
DataModelConditionListPredicate.DataModelConditionList.ListPath.DataModelGuid.Value,
|
||||
DataModelConditionListPredicate.DataModelConditionList.ListPath.Path
|
||||
);
|
||||
|
||||
return listDataModel.GetListTypeViewModel(_dataModelUIService);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user