diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs
similarity index 89%
rename from src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs
rename to src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs
index 72b693f5d..0b4b5cb03 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionPredicate.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DataModelConditionPredicate.cs
@@ -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
///
- public class DataModelConditionPredicate : DataModelConditionPart
+ public abstract class DataModelConditionPredicate : DataModelConditionPart
{
///
/// Creates a new instance of the class
///
///
///
- public DataModelConditionPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
+ /// A new empty entity
+ 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();
}
///
@@ -42,31 +39,117 @@ namespace Artemis.Core
///
/// Gets the operator
///
- public BaseConditionOperator? Operator { get; private set; }
+ public BaseConditionOperator? Operator { get; protected set; }
///
/// Gets the path of the left property
///
- public DataModelPath? LeftPath { get; private set; }
+ public DataModelPath? LeftPath { get; protected set; }
///
/// Gets the path of the right property
///
- public DataModelPath? RightPath { get; private set; }
+ public DataModelPath? RightPath { get; protected set; }
///
/// Gets the right static value, only used it is
///
///
- public object? RightStaticValue { get; private set; }
+ public object? RightStaticValue { get; protected set; }
internal DataModelConditionPredicateEntity Entity { get; set; }
+ ///
+ public override string ToString()
+ {
+ if (PredicateType == ProfileRightSideType.Dynamic)
+ return $"[Dynamic] {LeftPath} {Operator.Description} {RightPath}";
+ return $"[Static] {LeftPath} {Operator.Description} {RightStaticValue}";
+ }
+
+ #region IDisposable
+
+ ///
+ 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
+
///
/// Updates the left side of the predicate
///
/// The path pointing to the left side value inside the data model
- 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();
}
- ///
- 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());
- }
-
///
/// Determines the best type to use for the right side op this predicate
///
- 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;
- }
-
- ///
- public override string ToString()
- {
- if (PredicateType == ProfileRightSideType.Dynamic)
- return $"[Dynamic] {LeftPath} {Operator.Description} {RightPath}";
- return $"[Static] {LeftPath} {Operator.Description} {RightStaticValue}";
- }
-
- ///
- protected override void Dispose(bool disposing)
- {
- ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
- ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
-
- LeftPath?.Dispose();
- RightPath?.Dispose();
-
- base.Dispose(disposing);
- }
-
- ///
- 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
+
+ ///
+ 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());
+ }
+
+ ///
+ 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)
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs
new file mode 100644
index 000000000..2f29d2f40
--- /dev/null
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGeneralPredicate.cs
@@ -0,0 +1,63 @@
+using System;
+using Artemis.Storage.Entities.Profile.Conditions;
+
+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
+ ///
+ public class DataModelConditionGeneralPredicate : DataModelConditionPredicate
+ {
+ ///
+ /// Creates a new instance of the class
+ ///
+ ///
+ ///
+ public DataModelConditionGeneralPredicate(DataModelConditionPart parent, ProfileRightSideType predicateType)
+ : base(parent, predicateType, new DataModelConditionGeneralPredicateEntity())
+ {
+ Initialize();
+ }
+
+ internal DataModelConditionGeneralPredicate(DataModelConditionPart parent, DataModelConditionGeneralPredicateEntity entity)
+ : base(parent, entity)
+ {
+ Initialize();
+ }
+
+ #region Modification
+
+ ///
+ 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
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs
index 3c6cf18b9..d96d7065d 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionGroup.cs
@@ -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));
}
diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
index a297c65c2..06f520fe6 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionListPredicate.cs
@@ -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
{
///
/// A predicate like evaluated inside a
///
- public class DataModelConditionListPredicate : DataModelConditionPart
+ public class DataModelConditionListPredicate : DataModelConditionPredicate
{
///
/// Creates a new instance of the class
@@ -18,173 +14,97 @@ namespace Artemis.Core
///
///
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();
}
- ///
- /// Gets or sets the predicate type
- ///
- public ProfileRightSideType PredicateType { get; set; }
-
- ///
- /// Gets the operator
- ///
- public BaseConditionOperator? Operator { get; private set; }
-
///
/// Gets the data model condition list this predicate belongs to
///
public DataModelConditionList DataModelConditionList { get; private set; }
- ///
- /// Gets the path of the left property
- ///
- public DataModelPath? LeftPath { get; private set; }
+ private void ApplyParentList()
+ {
+ DataModelConditionPart? current = Parent;
+ while (current != null)
+ {
+ if (current is DataModelConditionList parentList)
+ {
+ DataModelConditionList = parentList;
+ return;
+ }
- ///
- /// Gets the path of the right property
- ///
- public DataModelPath? RightPath { get; private set; }
+ current = current.Parent;
+ }
- ///
- /// Gets the right static value, only used it is
- ///
- ///
- 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
///
/// Updates the left side of the predicate
///
/// The path pointing to the left side value inside the list
- 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);
}
- ///
- /// Updates the right side of the predicate using a path and makes the predicate dynamic
- ///
- /// The path pointing to the right side value
- 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;
- }
-
- ///
- /// Updates the right side of the predicate, makes the predicate static and re-compiles the expression
- ///
- /// The right side value to use
- public void UpdateRightSideStatic(object? staticValue)
- {
- PredicateType = ProfileRightSideType.Static;
- RightPath?.Dispose();
- RightPath = null;
-
- SetStaticValue(staticValue);
- }
-
- ///
- /// Updates the operator of the predicate and re-compiles the expression
- ///
- ///
- 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();
- }
-
- ///
- /// Not supported for list predicates, always returns false
- ///
- public override bool Evaluate()
- {
- return false;
- }
-
- ///
- /// Determines whether the provided path is contained inside the list
- ///
- /// The path to evaluate
- 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;
- }
-
- ///
- /// Determines the best type to use for the right side op this predicate
- ///
- public Type? GetPreferredRightSideType()
+ ///
+ public override Type? GetPreferredRightSideType()
{
Type? preferredType = Operator?.RightSideType;
Type? leftSideType = DataModelConditionList.IsPrimitiveList
@@ -199,22 +119,18 @@ namespace Artemis.Core
return preferredType;
}
- #region IDisposable
-
- ///
- protected override void Dispose(bool disposing)
- {
- ConditionOperatorStore.ConditionOperatorAdded -= ConditionOperatorStoreOnConditionOperatorAdded;
- ConditionOperatorStore.ConditionOperatorRemoved -= ConditionOperatorStoreOnConditionOperatorRemoved;
-
- LeftPath?.Dispose();
- RightPath?.Dispose();
-
- base.Dispose(disposing);
- }
-
#endregion
+ #region Evaluation
+
+ ///
+ /// Not supported for list predicates, always returns false
+ ///
+ 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
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Utilities/DeserializationLogger.cs b/src/Artemis.Core/Utilities/DeserializationLogger.cs
index e1c176283..de4424def 100644
--- a/src/Artemis.Core/Utilities/DeserializationLogger.cs
+++ b/src/Artemis.Core/Utilities/DeserializationLogger.cs
@@ -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);
diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionGeneralPredicateEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionGeneralPredicateEntity.cs
new file mode 100644
index 000000000..1a0fa93ea
--- /dev/null
+++ b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionGeneralPredicateEntity.cs
@@ -0,0 +1,6 @@
+namespace Artemis.Storage.Entities.Profile.Conditions
+{
+ public class DataModelConditionGeneralPredicateEntity : DataModelConditionPredicateEntity
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
index 513a9af43..cfc4b5372 100644
--- a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionListPredicateEntity.cs
@@ -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; }
-
}
}
\ No newline at end of file
diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionPredicateEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionPredicateEntity.cs
index 08ee41d25..c913a6a3c 100644
--- a/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionPredicateEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/Conditions/DataModelConditionPredicateEntity.cs
@@ -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; }
-
}
}
\ No newline at end of file
diff --git a/src/Artemis.Storage/Migrations/M6PredicateAbstraction.cs b/src/Artemis.Storage/Migrations/M6PredicateAbstraction.cs
new file mode 100644
index 000000000..3dd494e40
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/M6PredicateAbstraction.cs
@@ -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 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);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Artemis.UI.csproj.DotSettings b/src/Artemis.UI/Artemis.UI.csproj.DotSettings
new file mode 100644
index 000000000..7c2d2de36
--- /dev/null
+++ b/src/Artemis.UI/Artemis.UI.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
index 374948a90..d0bfc092b 100644
--- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
+++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
@@ -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);
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
similarity index 91%
rename from src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
rename to src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
index 08ea2cb05..d0542e439 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
@@ -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();
ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues");
-
- Initialize();
}
public DataModelConditionPredicate DataModelConditionPredicate => (DataModelConditionPredicate) Model;
public PluginSetting ShowDataModelValues { get; }
-
- public BindableCollection 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 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 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 GetSupportedInputTypes();
+ protected abstract Type GetLeftSideType();
+
+ protected virtual List 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 extra = GetExtraRightSideDataModelViewModels();
+ if (extra != null)
+ RightSideSelectionViewModel.ExtraDataModelViewModels.AddRange(extra);
}
private void CreateRightSideInputViewModel()
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs
index b5f3bad1f..3c5d63e93 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupViewModel.cs
@@ -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);
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs
deleted file mode 100644
index 31ad33c2c..000000000
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateViewModel.cs
+++ /dev/null
@@ -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 _operators;
- private DataModelStaticViewModel _rightSideInputViewModel;
- private DataModelDynamicViewModel _rightSideSelectionViewModel;
- private BaseConditionOperator _selectedOperator;
-
- private List _supportedInputTypes;
-
- public DataModelConditionListPredicateViewModel(
- DataModelConditionListPredicate dataModelConditionListPredicate,
- IProfileEditorService profileEditorService,
- IDataModelUIService dataModelUIService,
- IConditionOperatorService conditionOperatorService) : base(dataModelConditionListPredicate)
- {
- _profileEditorService = profileEditorService;
- _dataModelUIService = dataModelUIService;
- _conditionOperatorService = conditionOperatorService;
- _supportedInputTypes = new List();
-
- SelectOperatorCommand = new DelegateCommand(ExecuteSelectOperatorCommand);
- Operators = new BindableCollection();
-
- Initialize();
- }
-
- public DataModelConditionListPredicate DataModelConditionListPredicate => (DataModelConditionListPredicate) Model;
-
- public BindableCollection 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 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
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
index 7990bd83a..7bbf7a2d8 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListViewModel.cs
@@ -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();
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml
similarity index 97%
rename from src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml
rename to src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml
index 8bdc6a14e..931d22b7b 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml
@@ -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}}">
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml.cs
similarity index 74%
rename from src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml.cs
rename to src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml.cs
index 0891cd5fc..22411462b 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionPredicateView.xaml.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateView.xaml.cs
@@ -4,11 +4,11 @@ using System.Windows.Controls;
namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
///
- /// Interaction logic for DataModelConditionPredicateView.xaml
+ /// Interaction logic for DataModelConditionGeneralPredicateView.xaml
///
- public partial class DataModelConditionPredicateView : UserControl
+ public partial class DataModelConditionGeneralPredicateView : UserControl
{
- public DataModelConditionPredicateView()
+ public DataModelConditionGeneralPredicateView()
{
InitializeComponent();
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs
new file mode 100644
index 000000000..2b346da0f
--- /dev/null
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs
@@ -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 GetSupportedInputTypes()
+ {
+ IReadOnlyCollection editors = _dataModelUIService.RegisteredDataModelEditors;
+ List 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateView.xaml
similarity index 100%
rename from src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateView.xaml
rename to src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateView.xaml
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateView.xaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateView.xaml.cs
similarity index 100%
rename from src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionListPredicateView.xaml.cs
rename to src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateView.xaml.cs
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs
new file mode 100644
index 000000000..6e5f9cabb
--- /dev/null
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs
@@ -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 GetSupportedInputTypes()
+ {
+ IReadOnlyCollection editors = _dataModelUIService.RegisteredDataModelEditors;
+ List 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 GetExtraRightSideDataModelViewModels()
+ {
+ if (GetListDataModel()?.Children?.FirstOrDefault() is DataModelPropertiesViewModel listValue)
+ return new List {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);
+ }
+ }
+}
\ No newline at end of file