DynamicProblemsColumn.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media.Imaging;
  7. using InABox.Clients;
  8. using InABox.Core;
  9. using InABox.Wpf.Editors;
  10. using InABox.WPF;
  11. namespace InABox.DynamicGrid;
  12. public class DynamicProblemsColumn<TEntity> : DynamicImageColumn
  13. where TEntity : Entity, IRemotable, IPersistent, IProblems, new()
  14. {
  15. private static readonly BitmapImage _warning = Wpf.Resources.warning.AsBitmapImage();
  16. private static readonly BitmapImage _graywarning = Wpf.Resources.warning.AsGrayScale().AsBitmapImage();
  17. private readonly IDynamicGrid<TEntity> _parent;
  18. public Func<IIssues[], FrameworkElement?>? CustomiseEditor { get; set; }
  19. public Action<IIssues[], FrameworkElement?>? IssuesUpdated { get; set; }
  20. public DynamicProblemsColumn(IDynamicGrid<TEntity> parent)
  21. {
  22. Image = IssuesImage;
  23. GetFilter = () => new FuncCheckBoxDynamicGridColumnFilter(DoFilterIssues, FilterData);
  24. ContextMenu = CreateIssuesMenu;
  25. ToolTip = CreateIssuesToolTip;
  26. _parent = parent;
  27. Position = DynamicActionColumnPosition.Start;
  28. if (typeof(TEntity).GetInterfaceDefinition(typeof(IProblems<>)) is Type problemInterface)
  29. {
  30. var tProblem = problemInterface.GenericTypeArguments[0];
  31. foreach(var column in DynamicGridUtils.LoadEditorColumns(tProblem))
  32. {
  33. _parent.AddHiddenColumn(nameof(IProblems.Problem) + "." + column.Name);
  34. }
  35. }
  36. }
  37. private IEnumerable<Tuple<string, object?>> FilterData()
  38. {
  39. yield return new("Active Issues", true);
  40. yield return new("No Issues", false);
  41. }
  42. private bool DoFilterIssues(CoreRow row, Predicate<object?> filter)
  43. {
  44. var hasIssues = row?.Get<TEntity, string[]>(x => x.Problem.Notes)?.Any() == true;
  45. return filter(hasIssues);
  46. }
  47. private BitmapImage? IssuesImage(CoreRow? row)
  48. {
  49. if (row?.Get<TEntity,string[]>(x=>x.Problem.Notes)?.Any() != true)
  50. return null;
  51. return row?.Get<TEntity,DateTime>(x=>x.Problem.Resolved).IsEmpty() == true
  52. ? _warning
  53. : _graywarning;
  54. }
  55. private FrameworkElement? CreateIssuesToolTip(DynamicActionColumn column, CoreRow? row)
  56. {
  57. var text = row?.Get<TEntity, string[]>(x => x.Problem.Notes) ?? new string[] { };
  58. return TextToolTip(NotesEditor.FormatNotes(text));
  59. }
  60. private MenuItem CreateMenu(string caption, RoutedEventHandler click)
  61. {
  62. var item = new MenuItem();
  63. item.Header = caption;
  64. item.Click += click;
  65. return item;
  66. }
  67. private ContextMenu? CreateIssuesMenu(CoreRow[]? rows)
  68. {
  69. if (rows is null || rows.Length == 0) return null;
  70. if (!Security.CanManageProblems<TEntity>())
  71. return null;
  72. var issues = rows.Any(r => r.Get<TEntity, string[]>(x => x.Problem.Notes).Length > 0);
  73. var result = new ContextMenu();
  74. if (!issues)
  75. {
  76. result.Items.Add(CreateMenu("Create Issue", (o, e) => EditIssues(rows)));
  77. }
  78. else if(rows.Length > 1)
  79. {
  80. result.Items.Add(CreateMenu("Add Issue", (o, e) => AddIssue(rows)));
  81. }
  82. else
  83. {
  84. result.Items.Add(CreateMenu("Update Issues", (o, e) => EditIssues(rows)));
  85. if (Security.CanManageProblems<TEntity>())
  86. {
  87. result.Items.Add(new Separator());
  88. result.Items.Add(CreateMenu("Mark as Resolved", (o, e) => ResolveIssues(rows)));
  89. }
  90. }
  91. return result;
  92. }
  93. private void ResolveIssues(CoreRow[] rows)
  94. {
  95. var row = rows[0];
  96. var entity = row.ToObject<TEntity>();
  97. entity.Problem.Resolved = DateTime.Now;
  98. using (new WaitCursor())
  99. Client.Save(entity, "Resolving Issues", (o, e) => { });
  100. // False here to prevent Refreshing and losing the selected row record
  101. _parent.UpdateRow<TEntity, DateTime>(row, x=>x.Problem.Resolved, entity.Problem.Resolved);
  102. // if (MessageBox.Show("This will clear the flagged issues for these items!\n\nAre you sure you wish to continue?", "Confirm",
  103. // MessageBoxButton.YesNo) == MessageBoxResult.Yes)
  104. // {
  105. // var _updates = LoadIssues(rows).ToArray();
  106. // foreach (var update in _updates)
  107. // {
  108. // update.Issues = "";
  109. // }
  110. // using (new WaitCursor())
  111. // {
  112. // Client.Save(_updates, "Clearing Issues", (o, e) => { });
  113. // }
  114. //
  115. // // False here to prevent Refreshing and losing the selected row record
  116. // foreach (var row in rows)
  117. // _parent.UpdateRow(row, IssuesProperty, "");
  118. // }
  119. }
  120. private void AddIssue(CoreRow[] rows)
  121. {
  122. var entities = rows.ToArray<TEntity>();
  123. var issue = "";
  124. if(TextEdit.Execute("Enter new issue: ", ref issue) && !issue.IsNullOrWhiteSpace())
  125. {
  126. foreach(var entity in entities)
  127. {
  128. entity.Problem.Notes = entity.Problem.Notes.Concatenate([issue]);
  129. }
  130. Client.Save(entities, "Saving Issues", (o, e) => { });
  131. _parent.UpdateRows(rows, entities);
  132. }
  133. }
  134. private void EditIssues(CoreRow[] rows)
  135. {
  136. var entities = rows.ToArray<TEntity>();
  137. var _grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicItemsListGrid<>), entities.First().Problem.GetType());
  138. if (_grid.EditItems(entities.ToArray(x => x.Problem)))
  139. {
  140. using (new WaitCursor())
  141. Client.Save(entities, "Saving Issues", (o, e) => { });
  142. _parent.UpdateRows(rows, entities);
  143. }
  144. }
  145. }