ScanGrid.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using InABox.DynamicGrid;
  5. using InABox.WPF;
  6. using Syncfusion.Pdf;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows;
  14. using System.Windows.Controls;
  15. namespace PRSDesktop
  16. {
  17. public class ScanGrid : DynamicDataGrid<Scan>
  18. {
  19. private List<ScanTag>? _tags;
  20. private Button? ExplodeBtn;
  21. public delegate void SelectAppliesTo(string appliesTo);
  22. public event SelectAppliesTo? OnSelectAppliesTo;
  23. public ScanGrid()
  24. {
  25. Options.BeginUpdate()
  26. .Clear()
  27. .Add(DynamicGridOption.MultiSelect)
  28. .Add(DynamicGridOption.DragSource)
  29. .Add(DynamicGridOption.SelectColumns)
  30. .EndUpdate();
  31. if (Security.CanEdit<Scan>() || Security.IsAllowed<CanSetupScanTags>())
  32. {
  33. ActionColumns.Add(new DynamicMenuColumn(MenuBuild, null));
  34. }
  35. // if (Security.CanEdit<Scan>())
  36. // {
  37. // ExplodeBtn = AddButton("Explode", null, Explode_Click);
  38. // }
  39. HiddenColumns.Add(x => x.Tag.ID);
  40. HiddenColumns.Add(x => x.Tag.AppliesTo);
  41. HiddenColumns.Add(x => x.Document.ID);
  42. }
  43. protected override void SelectItems(CoreRow[]? rows)
  44. {
  45. base.SelectItems(rows);
  46. if(ExplodeBtn is not null)
  47. {
  48. ExplodeBtn.Visibility = rows is not null && rows.Any() ? Visibility.Visible : Visibility.Collapsed;
  49. }
  50. }
  51. public void DoExplode()
  52. {
  53. if (DoExplode(SelectedRows))
  54. Refresh(false,true);
  55. }
  56. private bool Explode_Click(Button button, CoreRow[] rows)
  57. {
  58. return DoExplode(rows);
  59. }
  60. private bool DoExplode(CoreRow[] rows)
  61. {
  62. Guid tagID = Guid.Empty;
  63. foreach (var row in rows)
  64. {
  65. var rowTag = row.Get<Scan, Guid>(x => x.Tag.ID);
  66. if (tagID == Guid.Empty)
  67. {
  68. tagID = rowTag;
  69. }
  70. else if (rowTag != tagID)
  71. {
  72. tagID = Guid.Empty;
  73. break;
  74. }
  75. }
  76. var docIDs = rows.Select(x => x.Get<Scan, Guid>(x => x.Document.ID)).ToArray();
  77. var docs = new Client<Document>()
  78. .Query(
  79. new Filter<Document>(x => x.ID).InList(docIDs),
  80. new Columns<Document>(x => x.ID).Add(x => x.Data).Add(x => x.FileName))
  81. .ToObjects<Document>().ToDictionary(x => x.ID, x => x);
  82. var pages = new List<DocumentManipulationWindow.Page>();
  83. string filename = "";
  84. foreach (var docID in docIDs)
  85. {
  86. if (docs.TryGetValue(docID, out var doc))
  87. {
  88. filename = doc.FileName;
  89. var ms = new MemoryStream(doc.Data);
  90. var pdfDoc = DocumentManipulationWindow.RenderToPDF(doc.FileName, ms);
  91. foreach (var page in DocumentManipulationWindow.SplitIntoPages(doc.FileName, pdfDoc))
  92. {
  93. pages.Add(page);
  94. }
  95. }
  96. }
  97. if (ShowDocumentWindow(pages, filename, tagID))
  98. {
  99. // ShowDocumentWindow already saves new scans, so we just need to get rid of the old ones.
  100. DeleteItems(rows);
  101. return true;
  102. }
  103. return false;
  104. }
  105. private bool SetupTags_Click(System.Windows.Controls.Button button, CoreRow[] rows)
  106. {
  107. var list = new MasterList(typeof(ScanTag));
  108. if (list.ShowDialog() == true)
  109. return true;
  110. return false;
  111. }
  112. public static List<ScanTag> GetVisibleScanTagList()
  113. {
  114. var tags = new Client<ScanTag>().Query().ToObjects<ScanTag>().ToList();
  115. var tagsList = new List<ScanTag>();
  116. foreach (var tag in tags)
  117. {
  118. var entity = CoreUtils.GetEntityOrNull(tag.AppliesTo);
  119. if (entity is null || Security.CanView(entity))
  120. {
  121. var tagHasEmployee = new Client<ScanTagDistributionEmployee>()
  122. .Query(
  123. new Filter<ScanTagDistributionEmployee>(x => x.Tag.ID).IsEqualTo(tag.ID)
  124. .And(x => x.Employee.ID).IsEqualTo(App.EmployeeID),
  125. new Columns<ScanTagDistributionEmployee>(x => x.ID))
  126. .Rows.Any();
  127. if (tagHasEmployee)
  128. {
  129. tagsList.Add(tag);
  130. }
  131. }
  132. }
  133. return tagsList;
  134. }
  135. private List<ScanTag> GetVisibleTags()
  136. {
  137. _tags ??= GetVisibleScanTagList();
  138. return _tags;
  139. }
  140. private void MenuBuild(DynamicMenuColumn column, CoreRow? row)
  141. {
  142. if (row is null) return;
  143. if (Security.CanEdit<Scan>() || Security.IsAllowed<CanSetupScanTags>())
  144. {
  145. var changeTag = column.AddItem("Change Tag", null, null);
  146. changeTag.AddItem("(No Tag)", null, new Tuple<CoreRow, ScanTag?>(row, null), SetTag_Click);
  147. foreach (var tag in GetVisibleTags())
  148. {
  149. changeTag.AddItem(tag.Name, null, new Tuple<CoreRow, ScanTag?>(row, tag), SetTag_Click);
  150. }
  151. }
  152. if (Security.CanEdit<Scan>())
  153. {
  154. var processed = row.Get<Scan, bool>(x => x.Processed);
  155. column.AddItem(processed ? "Mark as not processed" : "Mark as processed", null, Process_Click);
  156. }
  157. if(OnSelectAppliesTo is not null)
  158. {
  159. column.AddItem("Go to Document", null, Document_Click);
  160. }
  161. }
  162. private void Document_Click(CoreRow? row)
  163. {
  164. if (row is null) return;
  165. OnSelectAppliesTo?.Invoke(row.Get<Scan, string>(x => x.Tag.AppliesTo));
  166. }
  167. private void SetTag_Click(Tuple<CoreRow, ScanTag?> obj)
  168. {
  169. var scan = obj.Item1.ToObject<Scan>();
  170. scan.Tag.ID = obj.Item2?.ID ?? Guid.Empty;
  171. SaveItem(scan);
  172. Refresh(false, true);
  173. }
  174. private void Process_Click(CoreRow? row)
  175. {
  176. if (row is null) return;
  177. var scan = row.ToObject<Scan>();
  178. if (!scan.Processed && MessageBox.Show("Doing this will remove this scan from the list. Do you wish to continue?", "Confirm", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  179. {
  180. return;
  181. }
  182. scan.Processed = !scan.Processed;
  183. SaveItem(scan);
  184. Refresh(false, true);
  185. }
  186. protected override void OnRowsDragStart(CoreRow[] rows)
  187. {
  188. var table = new CoreTable();
  189. table.Columns.Add(new CoreColumn { ColumnName = "ID", DataType = typeof(Guid) });
  190. foreach(var row in rows)
  191. {
  192. var newRow = table.NewRow();
  193. newRow.Set<Document, Guid>(x => x.ID, row.Get<Scan, Guid>(x => x.Document.ID));
  194. table.Rows.Add(newRow);
  195. }
  196. DragTable(typeof(Document), table);
  197. }
  198. public void UploadDocument(string filename, byte[] data, Guid tagID)
  199. {
  200. var document = new Document
  201. {
  202. FileName = filename,
  203. CRC = CoreUtils.CalculateCRC(data),
  204. TimeStamp = DateTime.Now,
  205. Data = data
  206. };
  207. new Client<Document>().Save(document, "");
  208. var scan = new Scan();
  209. scan.Document.ID = document.ID;
  210. scan.Tag.ID = tagID;
  211. scan.Employee.ID = App.EmployeeID;
  212. scan.Thumbnail = ImageUtils.GetPDFThumbnail(data, 256, 256);
  213. new Client<Scan>().Save(scan, "");
  214. Dispatcher.Invoke(() =>
  215. {
  216. Refresh(false, true);
  217. });
  218. }
  219. private static PdfDocumentBase CombinePages(IEnumerable<DocumentManipulationWindow.Page> pages)
  220. {
  221. var document = new PdfDocument();
  222. foreach (var page in pages)
  223. {
  224. document.ImportPage(page.Pdf, page.PageIndex);
  225. }
  226. return document;
  227. }
  228. public bool ShowDocumentWindow(List<DocumentManipulationWindow.Page> pages, string filename, Guid tagID)
  229. {
  230. var window = new DocumentManipulationWindow(pages, filename, tagID);
  231. if (window.ShowDialog() == true)
  232. {
  233. Progress.ShowModal("Uploading Files", (progress) =>
  234. {
  235. foreach (var group in window.Groups)
  236. {
  237. progress.Report($"Uploading '{group.FileName}'");
  238. var doc = CombinePages(group.Pages);
  239. byte[] data;
  240. using (var ms = new MemoryStream())
  241. {
  242. doc.Save(ms);
  243. data = ms.ToArray();
  244. }
  245. UploadDocument(group.FileName, data, group.TagID);
  246. }
  247. });
  248. return true;
  249. }
  250. return false;
  251. }
  252. protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
  253. {
  254. ShowDocumentWindow(new(), "", Guid.Empty);
  255. }
  256. protected override void GenerateColumns(DynamicGridColumns columns)
  257. {
  258. columns.Add<Scan, string>(x => x.Document.FileName, 0, "Filename", "", InABox.Core.Alignment.MiddleLeft);
  259. columns.Add<Scan, string>(x => x.Tag.Name, 100, "Tag", "", InABox.Core.Alignment.MiddleLeft);
  260. }
  261. protected override void Reload(Filters<Scan> criteria, Columns<Scan> columns, ref SortOrder<Scan>? sort, Action<CoreTable?, Exception?> action)
  262. {
  263. criteria.Add(new Filter<Scan>(x => x.Processed).IsEqualTo(false));
  264. var tagFilter = new Filter<Scan>(x => x.Tag.ID).InList(GetVisibleTags().Select(x => x.ID).ToArray());
  265. if (Security.IsAllowed<CanSetupScanTags>())
  266. {
  267. tagFilter.Or(x => x.Tag.ID).IsEqualTo(Guid.Empty);
  268. }
  269. criteria.Add(tagFilter);
  270. base.Reload(criteria, columns, ref sort, action);
  271. }
  272. }
  273. }