ScanGrid.cs 11 KB

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