ScheduleItemGrid.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media.Imaging;
  7. using Comal.Classes;
  8. using InABox.Clients;
  9. using InABox.Core;
  10. using InABox.DynamicGrid;
  11. using InABox.WPF;
  12. using Microsoft.Win32;
  13. using Syncfusion.Linq;
  14. using Button = System.Windows.Controls.Button;
  15. using MessageBox = System.Windows.MessageBox;
  16. using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
  17. using SaveFileDialog = Microsoft.Win32.SaveFileDialog;
  18. namespace PRS.Shared
  19. {
  20. internal class ScheduleItemGrid : DynamicDataGrid<Schedule>
  21. {
  22. private readonly BitmapImage disabled = PRS.Shared.Resources.disabled.AsBitmapImage();
  23. private readonly BitmapImage tick = PRS.Shared.Resources.tick.AsBitmapImage();
  24. protected override void Init()
  25. {
  26. base.Init();
  27. ActionColumns.Add(new DynamicTickColumn<Schedule, bool>(x => x.Active, tick, tick, disabled, CheckClick));
  28. HiddenColumns.Add(x => x.Active);
  29. HiddenColumns.Add(x => x.Title);
  30. HiddenColumns.Add(x => x.DocumentClass);
  31. AddButton("Export", PRS.Shared.Resources.download.AsBitmapImage(), SaveSchedules);
  32. AddButton("Import", PRS.Shared.Resources.upload.AsBitmapImage(), LoadSchedules);
  33. }
  34. protected override void DoReconfigure(FluentList<DynamicGridOption> options)
  35. {
  36. base.DoReconfigure(options);
  37. options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.SelectColumns, DynamicGridOption.MultiSelect);
  38. }
  39. public CoreTable Schedules { get; set; }
  40. public Type DocumentType { get; set; }
  41. public Guid DocumentID { get; set; }
  42. private bool LoadSchedules(Button sender, CoreRow[] rows)
  43. {
  44. if (rows.Length != 1)
  45. {
  46. MessageBox.Show("Please select only one row to process");
  47. return false;
  48. }
  49. var row = rows.First();
  50. var dlg = new OpenFileDialog();
  51. dlg.Filter = "PRS Schedule Files (*.schedule)|*.schedule";
  52. if (dlg.ShowDialog() == true)
  53. {
  54. Progress.Show("");
  55. var json = File.ReadAllText(dlg.FileName);
  56. Schedule[] schedules = { };
  57. try
  58. {
  59. schedules = Serialization.Deserialize<Schedule[]>(json);
  60. }
  61. catch
  62. {
  63. Progress.Close();
  64. MessageBox.Show("[" + Path.GetFileName(dlg.FileName) + "] is not a valid schedule file!");
  65. return false;
  66. }
  67. if (!schedules.Any())
  68. {
  69. Progress.Close();
  70. MessageBox.Show("[" + Path.GetFileName(dlg.FileName) + "] does not contain any schedules!");
  71. return false;
  72. }
  73. foreach (var schedule in schedules)
  74. {
  75. schedule.DocumentID = DocumentID;
  76. schedule.DocumentClass = DocumentType.EntityName();
  77. schedule.ID = Guid.Empty;
  78. schedule.Active = false;
  79. schedule.DueDate = DateTime.MinValue;
  80. }
  81. new Client<Schedule>().Save(schedules, "Imported from [" + Path.GetFileName(dlg.FileName) + "]");
  82. Progress.Close();
  83. MessageBox.Show(string.Format("{0} schedules loaded from [{1}]", schedules.Length, Path.GetFileName(dlg.FileName)));
  84. }
  85. return true;
  86. }
  87. private bool SaveSchedules(Button sender, CoreRow[] rows)
  88. {
  89. if (rows.Any())
  90. {
  91. MessageBox.Show("Please select at least one schedule before Exporting!");
  92. return false;
  93. }
  94. var names = new List<string>();
  95. rows.ForEach(r => names.Add(r.Get<Schedule, string>(c => c.Title)));
  96. var filename = DocumentType.Name + " (" + string.Join(" + ", names) + ")";
  97. Path.GetInvalidFileNameChars().ForEach(c => filename = filename.Replace(c.ToString(), ""));
  98. Path.GetInvalidPathChars().ForEach(c => filename = filename.Replace(c.ToString(), ""));
  99. var dlg = new SaveFileDialog();
  100. dlg.Filter = "PRS Schedule Files (*.schedule)|*.schedule";
  101. dlg.FileName = filename + ".schedule";
  102. dlg.AddExtension = false;
  103. if (dlg.ShowDialog() == true)
  104. {
  105. Progress.Show("");
  106. Filter<Schedule> filter = null;
  107. foreach (var schedule in SelectedRows)
  108. if (filter == null)
  109. filter = new Filter<Schedule>(x => x.ID).IsEqualTo(schedule.Get<Schedule, Guid>(x => x.ID));
  110. else
  111. filter = filter.Or(x => x.ID).IsEqualTo(schedule.Get<Schedule, Guid>(x => x.ID));
  112. var schedules = new Client<Schedule>().Load(filter);
  113. foreach (var schedule in schedules)
  114. {
  115. schedule.DocumentID = DocumentID;
  116. schedule.DocumentClass = DocumentType.EntityName();
  117. schedule.ID = Guid.Empty;
  118. schedule.Active = false;
  119. schedule.DueDate = DateTime.MinValue;
  120. }
  121. var json = Serialization.Serialize(schedules);
  122. File.WriteAllText(dlg.FileName + ".schedule", json);
  123. Progress.Close();
  124. MessageBox.Show(string.Format("{0} schedules saved to [{1}]", SelectedRows.Length, Path.GetFileName(dlg.FileName)));
  125. }
  126. return false;
  127. }
  128. private bool CheckClick(CoreRow row)
  129. {
  130. var Due = row.Get<Schedule, DateTime>(x => x.DueDate);
  131. if (Due.Equals(DateTime.MinValue))
  132. {
  133. MessageBox.Show("Schedule must have a due date!");
  134. return false;
  135. }
  136. using (var client = new Client<Schedule>())
  137. {
  138. var schedule = client.Query(
  139. new Filter<Schedule>(x => x.ID).IsEqualTo(row.Get<Schedule, Guid>(x => x.ID)),
  140. new Columns<Schedule>(x => x.ID).Add(x => x.Active)).ToObjects<Schedule>().FirstOrDefault();
  141. schedule.Active = !schedule.Active;
  142. client.Save(schedule, schedule.Active ? "Activated Schedule" : "Disabled Schedule");
  143. }
  144. return true;
  145. }
  146. public override void ConfigureColumns(DynamicGridColumns columns /*, bool dolookups = true */)
  147. {
  148. var colDocType = columns.Where(x => x.ColumnName.Equals("DocumentType")).FirstOrDefault();
  149. if (colDocType != null)
  150. columns.Remove(colDocType);
  151. var colRollover = columns.Where(x => x.ColumnName.Equals("Rollover")).FirstOrDefault();
  152. if (colRollover != null)
  153. colRollover.Lookups = new Dictionary<object, object>
  154. {
  155. { ScheduleRollover.FromActualDate, "From Actual" },
  156. { ScheduleRollover.FromDueDate, "From Due" }
  157. };
  158. var colPeriod = columns.Where(x => x.ColumnName.Equals("Period")).FirstOrDefault();
  159. if (colPeriod != null)
  160. colPeriod.Lookups = new Dictionary<object, object>
  161. {
  162. { SchedulePeriod.Year, "Years" },
  163. { SchedulePeriod.Month, "Months" },
  164. { SchedulePeriod.Week, "Weeks" },
  165. { SchedulePeriod.Day, "Days" },
  166. { SchedulePeriod.Hour, "Hours" },
  167. { SchedulePeriod.Minute, "Minutes" }
  168. };
  169. var colTrigger = columns.Where(x => x.ColumnName.Equals("Trigger")).FirstOrDefault();
  170. if (colTrigger != null)
  171. colTrigger.Lookups = new Dictionary<object, object>
  172. {
  173. { ScheduleTrigger.Distance, "Distance Travelled" },
  174. { ScheduleTrigger.Usage, "Usage Time" },
  175. { ScheduleTrigger.Counter1, "Counter 1" },
  176. { ScheduleTrigger.Counter2, "Counter 2" },
  177. { ScheduleTrigger.Counter3, "Counter 3" },
  178. { ScheduleTrigger.Counter4, "Counter 4" },
  179. { ScheduleTrigger.Counter5, "Counter 5" }
  180. };
  181. var colScheduleType = columns.Where(x => x.ColumnName.Equals("ScheduleType")).FirstOrDefault();
  182. if (colScheduleType != null)
  183. colScheduleType.Lookups = new Dictionary<object, object>
  184. {
  185. { ScheduleType.Job, "Job" },
  186. { ScheduleType.Task, "Task" }
  187. };
  188. base.ConfigureColumns(columns /*,dolookups */);
  189. }
  190. //protected override void DeleteItem(DataRow row)
  191. //{
  192. // Items.Remove(Items[row.Index]);
  193. //}
  194. //public override ScheduleItem LoadItem(DataRow row)
  195. //{
  196. // return Items[row.Index];
  197. //}
  198. //protected override DataTable Reload(Dictionary<string, object> criteria, List<string> columns, string sort)
  199. //{
  200. // criteria.Add("DocumentID", DocumentID);
  201. // return base.Reload(criteria, columns, sort);
  202. //}
  203. protected override void Reload(Filters<Schedule> criteria, Columns<Schedule> columns, ref SortOrder<Schedule>? sort, Action<CoreTable?, Exception?> action)
  204. {
  205. criteria.Add(new Filter<Schedule>(x => x.DocumentID).IsEqualTo(DocumentID));
  206. sort = new SortOrder<Schedule>(x => x.DueDate);
  207. base.Reload(criteria, columns, ref sort, action);
  208. }
  209. public override Schedule CreateItem()
  210. {
  211. if(DocumentType is null)
  212. {
  213. throw new Exception("Cannot create item when DocumentType is null.");
  214. }
  215. var schedule = base.CreateItem();
  216. schedule.DocumentClass = DocumentType.EntityName();
  217. schedule.DocumentID = DocumentID;
  218. if (DocumentType == typeof(CustomModule) || DocumentType == typeof(ScheduledScript))
  219. schedule.ScheduleType = ScheduleType.None;
  220. return schedule;
  221. }
  222. public override void SaveItem(Schedule item)
  223. {
  224. if(DocumentType is not null)
  225. {
  226. item.DocumentClass = DocumentType.EntityName();
  227. }
  228. else
  229. {
  230. if (string.IsNullOrWhiteSpace(item.DocumentClass))
  231. {
  232. throw new Exception("Cannot save item when DocumentType is null.");
  233. }
  234. }
  235. base.SaveItem(item);
  236. }
  237. protected override void DoReconfigureEditors(DynamicEditorGrid grid, Schedule[] items)
  238. {
  239. base.DoReconfigureEditors(grid, items);
  240. var frequency = grid.FindEditor("Frequency");
  241. if (frequency != null)
  242. {
  243. var freq = (int)frequency.GetValue("Frequency");
  244. var period = grid.FindEditor("Period");
  245. period?.SetEnabled(freq > 0);
  246. var due = grid.FindEditor("DueDate");
  247. due?.SetEnabled(freq > 0);
  248. }
  249. var threshold = grid.FindEditor("Threshold");
  250. if (threshold != null)
  251. {
  252. var thresh = (int)threshold.GetValue("Threshold");
  253. var trigger = grid.FindEditor("Trigger");
  254. trigger?.SetEnabled(thresh > 0);
  255. var next = grid.FindEditor("DueThreshold");
  256. next?.SetEnabled(thresh > 0);
  257. }
  258. var scheduleTypeEditor = grid.FindEditor("ScheduleType");
  259. if(scheduleTypeEditor != null)
  260. {
  261. var scheduleType = (ScheduleType)scheduleTypeEditor.GetValue("ScheduleType");
  262. var taskTypeEditor = grid.FindEditor(nameof(Schedule.KanbanType));
  263. taskTypeEditor?.SetEnabled(scheduleType == ScheduleType.Task);
  264. }
  265. }
  266. protected override Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, Schedule[] items, string name, object value)
  267. {
  268. return base.EditorValueChanged(editor, items, name, value);
  269. }
  270. protected override BaseEditor? GetEditor(object item, DynamicGridColumn column)
  271. {
  272. var types = new List<Type> { typeof(CustomModule), typeof(ScheduledScript), typeof(Employee), typeof(Equipment) };
  273. var columns = new List<string> { "ScheduleType" };
  274. var schedule = (Schedule)item;
  275. var documentType = schedule.DocumentType();
  276. if (documentType == typeof(CustomModule) || documentType == typeof(ScheduledScript))
  277. columns.AddRange(new[]
  278. {
  279. "Description", "LeadTime", "EmployeeLink.ID", "ManagerLink.ID", "Report.ID", "Threshold", "Trigger", "DueThreshold", "Rollover",
  280. "QAForm"
  281. });
  282. else if (documentType == typeof(Employee))
  283. columns.AddRange(new[] { "Description", "EmployeeLink.ID", "Threshold", "Trigger", "DueThreshold" });
  284. else if (documentType == typeof(Customer))
  285. columns.AddRange(new[] { "Threshold", "Trigger", "DueThreshold" });
  286. if (types.Contains(documentType) && columns.Contains(column.ColumnName))
  287. return new NullEditor();
  288. return base.GetEditor(item, column);
  289. }
  290. public override DynamicEditorPages LoadEditorPages(Schedule item)
  291. {
  292. var pages = base.LoadEditorPages(item);
  293. foreach (var page in pages.ToArray())
  294. {
  295. if (page is IDynamicOneToManyGrid<Schedule, Kanban> && item.ScheduleType != ScheduleType.Task)
  296. pages = new DynamicEditorPages(pages.Where(x => x != page));
  297. else if (page is IDynamicOneToManyGrid<Schedule, Job> && item.ScheduleType != ScheduleType.Job)
  298. pages = new DynamicEditorPages(pages.Where(x => x != page));
  299. }
  300. return pages;
  301. }
  302. protected override void DefineLookups(ILookupEditorControl sender, Schedule[] items, bool async = true)
  303. {
  304. base.DefineLookups(sender, items, async);
  305. }
  306. }
  307. }