EventTriggerGrid.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. using com.sun.xml.@internal.bind.v2.runtime;
  2. using InABox.Core;
  3. using InABox.DynamicGrid;
  4. using InABox.WPF;
  5. using Microsoft.CodeAnalysis.CSharp.Syntax;
  6. using PRS.Shared.Events;
  7. using PRS.Shared.Grids.EventEditor;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Controls;
  14. using System.Windows.Markup.Localizer;
  15. using System.Windows.Media;
  16. namespace PRS.Shared;
  17. public class EventTriggerContainer<TEvent, TDataModel> : BaseObject
  18. where TEvent : IEvent<TDataModel>
  19. where TDataModel : IEventDataModel
  20. {
  21. public IEventTriggerParent<TEvent, TDataModel>? Parent { get; set; }
  22. public IEventTrigger<TEvent, TDataModel> Trigger { get; set; }
  23. public string TriggerType => Trigger.GetType().GetCaption();
  24. public string Description => Trigger.Description;
  25. }
  26. public class EventTriggerGrid<TEvent, TDataModel> : DynamicItemsListGrid<EventTriggerContainer<TEvent, TDataModel>>
  27. where TEvent : IEvent<TDataModel>
  28. where TDataModel : IEventDataModel
  29. {
  30. public IEnumerable<IEventTrigger<TEvent, TDataModel>> EventTriggers => Items.Where(x => x.Parent is null).Select(x => x.Trigger);
  31. public EventTriggerGrid(IEnumerable<IEventTrigger<TEvent, TDataModel>> items)
  32. {
  33. foreach(var item in items)
  34. {
  35. AddItem(item, null);
  36. }
  37. }
  38. private EventTriggerContainer<TEvent, TDataModel> GetContainer(IEventTrigger<TEvent, TDataModel> item)
  39. {
  40. return Items.First(x => x.Trigger == item);
  41. }
  42. private void AddItem(IEventTrigger<TEvent, TDataModel> item, IEventTriggerParent<TEvent, TDataModel>? parent)
  43. {
  44. Items.Add(new EventTriggerContainer<TEvent, TDataModel>
  45. {
  46. Trigger = item,
  47. Parent = parent
  48. });
  49. if(item is IEventTriggerParent<TEvent, TDataModel> parentTrigger)
  50. {
  51. foreach(var child in parentTrigger.ChildTriggers)
  52. {
  53. AddItem(child, parentTrigger);
  54. }
  55. }
  56. }
  57. protected override IDynamicGridUIComponent CreateUIComponent()
  58. {
  59. var component = new DynamicGridTreeUIComponent<EventTriggerContainer<TEvent, TDataModel>, IEventTrigger<TEvent, TDataModel>?>(
  60. x => LoadItem(x).Trigger,
  61. x => LoadItem(x).Parent,
  62. null,
  63. (container, parent) =>
  64. {
  65. if (parent is IEventTriggerParent<TEvent, TDataModel> parentTrigger)
  66. {
  67. parentTrigger.ChildTriggers.Add(container.Trigger);
  68. container.Parent = parentTrigger;
  69. }
  70. })
  71. {
  72. Parent = this,
  73. };
  74. component.OnContextMenuOpening += Component_OnContextMenuOpening;
  75. return component;
  76. }
  77. private enum OperatorType
  78. {
  79. And,
  80. Or
  81. }
  82. private void Component_OnContextMenuOpening(CoreTreeNode<IEventTrigger<TEvent, TDataModel>?>? node, ContextMenu menu)
  83. {
  84. if(node is null)
  85. {
  86. PopulateAddMenu(menu, null, null);
  87. }
  88. else
  89. {
  90. var andItem = menu.AddItem("And", null, null);
  91. PopulateAddMenu(andItem, node.ID, OperatorType.And);
  92. var orItem = menu.AddItem("Or", null, null);
  93. PopulateAddMenu(orItem, node.ID, OperatorType.Or);
  94. }
  95. }
  96. protected override void DoReconfigure(DynamicGridOptions options)
  97. {
  98. base.DoReconfigure(options);
  99. options.AddRows = true;
  100. options.EditRows = true;
  101. options.DeleteRows = true;
  102. options.MultiSelect = true;
  103. }
  104. public override DynamicGridColumns GenerateColumns()
  105. {
  106. var cols = new DynamicGridColumns<EventTriggerContainer<TEvent, TDataModel>>();
  107. cols.Add(x => x.Description);
  108. return cols;
  109. }
  110. private void PopulateAddMenu(ItemsControl menu, IEventTrigger<TEvent, TDataModel>? trigger, OperatorType? op)
  111. {
  112. var types = EventUtils.GetEventTriggerTypes(typeof(TEvent));
  113. foreach(var type in types)
  114. {
  115. menu.AddMenuItem(type.GetCaption(), null, (type, trigger, op), MenuAdd_Click);
  116. }
  117. }
  118. private void MenuAdd_Click((Type type, IEventTrigger<TEvent, TDataModel>? trigger, OperatorType? op) tuple)
  119. {
  120. if (tuple.type.IsGenericType)
  121. {
  122. tuple.type = tuple.type.MakeGenericType(typeof(TEvent).GenericTypeArguments);
  123. }
  124. var trigger = (Activator.CreateInstance(tuple.type) as IEventTrigger<TEvent, TDataModel>)!;
  125. if (!EventTriggerEditors.EditTrigger(trigger))
  126. {
  127. return;
  128. }
  129. var container = new EventTriggerContainer<TEvent, TDataModel> { Trigger = trigger };
  130. if(tuple.trigger is not null)
  131. {
  132. // Insert index of 'trigger' into 'parent'
  133. int? parentInsertIndex = null;
  134. IEventTriggerParent<TEvent, TDataModel>? parent = null;
  135. var triggerContainer = GetContainer(tuple.trigger);
  136. if(tuple.op == OperatorType.And && triggerContainer.Trigger is AndTrigger<TEvent, TDataModel> andTrigger)
  137. {
  138. parent = andTrigger;
  139. parentInsertIndex = null;
  140. }
  141. else if(tuple.op == OperatorType.Or && triggerContainer.Trigger is OrTrigger<TEvent, TDataModel> orTrigger)
  142. {
  143. parent = orTrigger;
  144. parentInsertIndex = null;
  145. }
  146. else if(tuple.op == OperatorType.And && triggerContainer.Parent is AndTrigger<TEvent, TDataModel> andTrigger2)
  147. {
  148. parent = andTrigger2;
  149. parentInsertIndex = triggerContainer.Parent.ChildTriggers.IndexOf(triggerContainer.Trigger) + 1;
  150. }
  151. else if(tuple.op == OperatorType.Or && triggerContainer.Parent is OrTrigger<TEvent, TDataModel> orTrigger2)
  152. {
  153. parent = orTrigger2;
  154. parentInsertIndex = triggerContainer.Parent.ChildTriggers.IndexOf(triggerContainer.Trigger) + 1;
  155. }
  156. if(parent is not null)
  157. {
  158. container.Parent = parent;
  159. if (parentInsertIndex.HasValue && parentInsertIndex < parent.ChildTriggers.Count)
  160. {
  161. parent.ChildTriggers.Insert(parentInsertIndex.Value, trigger);
  162. }
  163. else
  164. {
  165. parent.ChildTriggers.Add(trigger);
  166. }
  167. }
  168. else
  169. {
  170. if(tuple.op == OperatorType.And)
  171. {
  172. parent = new AndTrigger<TEvent, TDataModel>();
  173. }
  174. else if(tuple.op == OperatorType.Or)
  175. {
  176. parent = new OrTrigger<TEvent, TDataModel>();
  177. }
  178. if(parent is not null)
  179. {
  180. int? itemsInsertIndex = null;
  181. var parentContainer = new EventTriggerContainer<TEvent, TDataModel>()
  182. {
  183. Trigger = parent,
  184. Parent = triggerContainer.Parent
  185. };
  186. if(triggerContainer.Parent is not null)
  187. {
  188. var index = triggerContainer.Parent.ChildTriggers.IndexOf(triggerContainer.Trigger);
  189. triggerContainer.Parent.ChildTriggers[index] = parent;
  190. }
  191. else
  192. {
  193. itemsInsertIndex = Items.IndexOf(triggerContainer);
  194. }
  195. triggerContainer.Parent = parent;
  196. container.Parent = parent;
  197. parent.ChildTriggers.Add(triggerContainer.Trigger);
  198. parent.ChildTriggers.Add(trigger);
  199. if (itemsInsertIndex.HasValue)
  200. {
  201. Items.Insert(itemsInsertIndex.Value, parentContainer);
  202. }
  203. else
  204. {
  205. Items.Add(parentContainer);
  206. }
  207. }
  208. }
  209. }
  210. Items.Add(container);
  211. RebuildItemsList();
  212. Refresh(false, true);
  213. DoChanged();
  214. }
  215. private void RebuildItemsList()
  216. {
  217. var triggers = Items.Where(x => x.Parent is null).Select(x => x.Trigger).ToArray();
  218. Items.Clear();
  219. foreach(var item in triggers)
  220. {
  221. AddItem(item, null);
  222. }
  223. }
  224. private IEnumerable<EventTriggerContainer<TEvent, TDataModel>> GetAllChildren(EventTriggerContainer<TEvent, TDataModel> item)
  225. {
  226. yield return item;
  227. if(item.Trigger is IEventTriggerParent<TEvent, TDataModel> parent)
  228. {
  229. foreach(var childItem in parent.ChildTriggers.SelectMany(x => GetAllChildren(GetContainer(x))))
  230. {
  231. yield return childItem;
  232. }
  233. }
  234. }
  235. public override void DeleteItems(params CoreRow[] rows)
  236. {
  237. var toDelete = rows.SelectMany(x => GetAllChildren(LoadItem(x))).ToArray();
  238. foreach(var item in toDelete)
  239. {
  240. item.Parent?.ChildTriggers.Remove(item.Trigger);
  241. Items.Remove(item);
  242. }
  243. }
  244. protected override void DoAdd(bool openEditorOnDirectEdit = false)
  245. {
  246. var menu = new ContextMenu();
  247. PopulateAddMenu(menu, null, null);
  248. menu.IsOpen = true;
  249. }
  250. protected override void DoEdit()
  251. {
  252. if (SelectedRows.Length != 1) return;
  253. var row = SelectedRows.First();
  254. var item = LoadItem(row);
  255. if (EventTriggerEditors.EditTrigger(item.Trigger))
  256. {
  257. UpdateRow(row, item);
  258. DoChanged();
  259. }
  260. }
  261. }