DigitalFormGrid.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Media.Imaging;
  10. using FastReport;
  11. using InABox.Clients;
  12. using InABox.Core;
  13. using InABox.Core.Reports;
  14. using InABox.Scripting;
  15. using InABox.Wpf;
  16. using InABox.WPF;
  17. using Microsoft.Win32;
  18. namespace InABox.DynamicGrid
  19. {
  20. public class DigitalFormExportData
  21. {
  22. public string Code { get; set; }
  23. public string Description { get; set; }
  24. public string AppliesTo { get; set; }
  25. public DigitalFormExportData() { }
  26. public DigitalFormExportData(DigitalForm form)
  27. {
  28. Code = form.Code;
  29. Description = form.Description;
  30. AppliesTo = form.AppliesTo;
  31. }
  32. public List<LayoutData> Layouts { get; set; }
  33. public List<VariableData> Variables { get; set; }
  34. public List<DocumentData> Documents { get; set; }
  35. public DigitalForm ToForm() => new DigitalForm
  36. {
  37. Code = Code,
  38. Description = Description,
  39. AppliesTo = AppliesTo
  40. };
  41. public class LayoutData
  42. {
  43. public string Code { get; set; }
  44. public string Description { get; set; }
  45. public DFLayoutType Type { get; set; }
  46. public string Layout { get; set; }
  47. public LayoutData() { }
  48. public LayoutData(DigitalFormLayout layout)
  49. {
  50. Code = layout.Code;
  51. Description = layout.Description;
  52. Type = layout.Type;
  53. Layout = layout.Layout;
  54. }
  55. public DigitalFormLayout ToLayout() => new DigitalFormLayout
  56. {
  57. Code = Code,
  58. Description = Description,
  59. Type = Type,
  60. Layout = Layout
  61. };
  62. }
  63. public class VariableData
  64. {
  65. public string Code { get; set; }
  66. public string Description { get; set; }
  67. public string VariableType { get; set; }
  68. public string Parameters { get; set; }
  69. public bool Required { get; set; }
  70. public bool Secure { get; set; }
  71. public bool Retain { get; set; }
  72. public bool Hidden { get; set; }
  73. public long Sequence { get; set; }
  74. public VariableData() { }
  75. public VariableData(DigitalFormVariable variable)
  76. {
  77. Code = variable.Code;
  78. Description = variable.Description;
  79. VariableType = variable.VariableType;
  80. Parameters = variable.Parameters;
  81. Required = variable.Required;
  82. Secure = variable.Secure;
  83. Retain = variable.Retain;
  84. Hidden = variable.Hidden;
  85. Sequence = variable.Sequence;
  86. }
  87. public DigitalFormVariable ToVariable() => new DigitalFormVariable
  88. {
  89. Code = Code,
  90. Description = Description,
  91. VariableType = VariableType,
  92. Parameters = Parameters,
  93. Required = Required,
  94. Secure = Secure,
  95. Retain = Retain,
  96. Hidden = Hidden,
  97. Sequence = Sequence
  98. };
  99. }
  100. public class DocumentData
  101. {
  102. public string FileName { get; set; }
  103. public byte[] Data { get; set; }
  104. public Guid ID { get; set; }
  105. public DocumentData() { }
  106. public DocumentData(Document document)
  107. {
  108. FileName = document.FileName;
  109. Data = document.Data;
  110. ID = document.ID;
  111. }
  112. public Document ToDocument() => new Document
  113. {
  114. FileName = FileName,
  115. Data = Data,
  116. TimeStamp = DateTime.Now,
  117. ID = ID
  118. };
  119. }
  120. }
  121. public class DigitalFormGrid : DynamicDataGrid<DigitalForm>
  122. {
  123. private bool _showall;
  124. private Button CopyForm = null!; // Late-initialised
  125. protected override void Init()
  126. {
  127. base.Init();
  128. AddButton("Show All", null, ShowAllClick);
  129. // TODO: Add back in
  130. //ActionColumns.Add(new DynamicImageColumn(ReportImage, ReportClick));
  131. AddButton("Groups", null, EditGroupsClick);
  132. CopyForm = AddButton("Copy Form", InABox.Wpf.Resources.copy.AsBitmapImage(), CopyForm_Click);
  133. CopyForm.IsEnabled = false;
  134. if (!Security.CanEdit<DigitalForm>())
  135. {
  136. CopyForm.Visibility = Visibility.Collapsed;
  137. }
  138. }
  139. protected override void DoReconfigure(FluentList<DynamicGridOption> options)
  140. {
  141. base.DoReconfigure(options);
  142. options.AddRange(DynamicGridOption.ImportData, DynamicGridOption.ExportData, DynamicGridOption.FilterRows);
  143. }
  144. protected override void SelectItems(CoreRow[]? rows)
  145. {
  146. base.SelectItems(rows);
  147. CopyForm.IsEnabled = rows is not null && rows.Length == 1;
  148. }
  149. private bool CopyForm_Click(Button btn, CoreRow[] rows)
  150. {
  151. if(rows.Length != 1)
  152. {
  153. MessageWindow.ShowMessage("Please select one form to copy.", "Invalid selection.");
  154. return false;
  155. }
  156. var form = rows[0].ToObject<DigitalForm>();
  157. Client.EnsureColumns(form,
  158. new Columns<DigitalForm>(x => x.Description)
  159. .Add(x => x.AppliesTo)
  160. .Add(x => x.Secure)
  161. .Add(x => x.Final)
  162. .Add(x => x.Group.ID));
  163. var newForm = new DigitalForm();
  164. newForm.Description = form.Description;
  165. newForm.AppliesTo = form.AppliesTo;
  166. newForm.Secure = form.Secure;
  167. newForm.Final = form.Final;
  168. newForm.Group.ID = form.Group.ID;
  169. var children = Client.QueryMultiple(
  170. new KeyedQueryDef<DigitalFormLayout>(
  171. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(form.ID),
  172. new Columns<DigitalFormLayout>(x => x.Code)
  173. .Add(x => x.Description)
  174. .Add(x => x.Type)
  175. .Add(x => x.Layout)
  176. .Add(x => x.Active)),
  177. new KeyedQueryDef<DigitalFormVariable>(
  178. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(form.ID),
  179. new Columns<DigitalFormVariable>(x => x.Code)
  180. .Add(x => x.Description)
  181. .Add(x => x.VariableType)
  182. .Add(x => x.Group)
  183. .Add(x => x.Parameters)
  184. .Add(x => x.Required)
  185. .Add(x => x.Secure)
  186. .Add(x => x.Retain)
  187. .Add(x => x.Hidden)
  188. .Add(x => x.Sequence)),
  189. new KeyedQueryDef<ReportTemplate>(
  190. new Filter<ReportTemplate>(x => x.Section).IsEqualTo(form.ID.ToString()),
  191. null),
  192. new KeyedQueryDef<DigitalFormDocument>(
  193. new Filter<DigitalFormDocument>(x => x.EntityLink.ID).IsEqualTo(form.ID),
  194. new Columns<DigitalFormDocument>(x => x.Type)
  195. .Add(x => x.DocumentLink.ID)
  196. .Add(x => x.Superceded)
  197. .Add(x => x.Thumbnail)
  198. .Add(x => x.Notes)));
  199. if (EditItems(new[] { newForm }, type =>
  200. {
  201. return children.GetOrDefault(type.Name);
  202. }))
  203. {
  204. return true;
  205. }
  206. else
  207. {
  208. return false;
  209. }
  210. }
  211. private bool EditGroupsClick(Button arg1, CoreRow[] arg2)
  212. {
  213. new MasterList(typeof(DigitalFormGroup)).ShowDialog();
  214. return false;
  215. }
  216. private BitmapImage? ReportImage(CoreRow arg)
  217. {
  218. return arg != null ? Wpf.Resources.printer.AsBitmapImage() : null;
  219. }
  220. /*private bool ReportClick(CoreRow arg)
  221. {
  222. if (arg == null)
  223. return false;
  224. var typename = arg.Get<DigitalForm, string>(c => c.AppliesTo);
  225. var formid = arg.Get<DigitalForm, Guid>(c => c.ID);
  226. // Get Applies To
  227. /*Type type = CoreUtils.GetEntity("Comal.Classes."+typename);
  228. CoreTable entity = new CoreTable();
  229. entity.LoadColumns(type);
  230. // Get Form Details
  231. CoreTable form = new CoreTable();
  232. form.Columns.Add(new CoreColumn() { ColumnName = "ID", DataType = typeof(Guid) });
  233. form.Columns.Add(new CoreColumn() { ColumnName = "Parent.ID", DataType = typeof(Guid) });
  234. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, String>(x => x.Form.Description, "."), DataType = typeof(String) });
  235. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, String>(x => x.FormCompletedBy.UserID, "."), DataType = typeof(String) });
  236. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, DateTime>(x => x.FormCompleted, "."), DataType = typeof(String) });
  237. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, String>(x => x.Location.Address, "."), DataType = typeof(String) });
  238. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, double>(x => x.Location.Latitude, "."), DataType = typeof(String) });
  239. form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName<IDigitalFormInstance, double>(x => x.Location.Longitude, "."), DataType = typeof(String) });
  240. var variables = new Client<DigitalFormVariable>().Query(new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(formid));
  241. foreach (var row in variables.Rows)
  242. {
  243. form.Columns.Add(
  244. new CoreColumn()
  245. {
  246. ColumnName = row.Get<DigitalFormVariable, String>(c => c.Code),
  247. DataType = DigitalFormVariable.DataType(row.Get<DigitalFormVariable, DigitalFormVariableType>(c => c.VariableType))
  248. }
  249. );
  250. }*
  251. // Create DataModel
  252. //DigitalFormReportDataModel model = new DigitalFormReportDataModel(form,entity,typename);
  253. AutoDataModel<DigitalForm> model = new AutoDataModel<DigitalForm>(new Filter<DigitalForm>(x => x.ID).IsEqualTo(formid));
  254. // Load Template
  255. var template = new Client<ReportTemplate>()
  256. .Load(new Filter<ReportTemplate>(x => x.Section).IsEqualTo("DigitalForms").And(x => x.Name).IsEqualTo(formid.ToString()))
  257. .FirstOrDefault();
  258. if (template == null)
  259. {
  260. template = new ReportTemplate
  261. {
  262. Section = "DigitalForms",
  263. Name = formid.ToString(),
  264. Visible = false
  265. };
  266. new Client<ReportTemplate>().Save(template, "");
  267. }
  268. ReportUtils.DesignReport(template, model);
  269. // Preview Report
  270. return false;
  271. }*/
  272. private bool ShowAllClick(Button arg1, CoreRow[] arg2)
  273. {
  274. _showall = !_showall;
  275. UpdateButton(arg1, null, _showall ? "Hide Inactive" : "Show All");
  276. return true;
  277. }
  278. protected override void Reload(Filters<DigitalForm> criteria, Columns<DigitalForm> columns, ref SortOrder<DigitalForm>? sort,
  279. Action<CoreTable?, Exception?> action)
  280. {
  281. if (!_showall)
  282. criteria.Add(new Filter<DigitalForm>(x => x.Active).IsEqualTo(true));
  283. base.Reload(criteria, columns, ref sort, action);
  284. }
  285. public override DynamicEditorPages LoadEditorPages(DigitalForm item)
  286. {
  287. var pages = base.LoadEditorPages(item);
  288. pages.Add(new DigitalFormReportGrid());
  289. return pages;
  290. }
  291. public override bool EditItems(DigitalForm[] items, Func<Type, CoreTable?>? PageDataHandler = null, bool PreloadPages = false)
  292. {
  293. // Need to do this to make sure that the variables are available to the layouts (and vice versa?)
  294. return base.EditItems(items, PageDataHandler, true);
  295. }
  296. private const string ExportFileFilter = "Excel Files (*.xls, *xlsx)|*.xls;*.xlsx|Digital Forms (*.prs-form)|*.prs-form";
  297. protected override void DoImport()
  298. {
  299. var dialog = new OpenFileDialog
  300. {
  301. Filter = ExportFileFilter
  302. };
  303. if (dialog.ShowDialog() != true)
  304. return;
  305. String extension = Path.GetExtension(dialog.FileName) ?? "";
  306. if (extension.ToLower().Equals(".xls") || extension.ToLower().Equals(".xlsx"))
  307. {
  308. String appliesto = "";
  309. String code = "";
  310. var lookups = new DigitalFormCategoryLookups(null).Lookups();
  311. if (!DictionaryEdit.Execute<String>(lookups, ref appliesto, "Applies To", "Select Form Type") || String.IsNullOrWhiteSpace(appliesto))
  312. return;
  313. Progress.ShowModal("Creating Form", (progress) =>
  314. {
  315. var codes = new Client<DigitalForm>().Query(
  316. null,
  317. new Columns<DigitalForm>(x => x.Code),
  318. null
  319. ).Rows.Select(r => r.Get<DigitalForm, String>(c => c.Code)).ToArray();
  320. int i = 1;
  321. code = Path.GetFileNameWithoutExtension(dialog.FileName).ToUpper();
  322. while (codes.Contains(code))
  323. code = $"{Path.GetFileNameWithoutExtension(dialog.FileName).ToUpper()} ({i++})";
  324. DigitalForm form = new DigitalForm();
  325. form.Code = code;
  326. form.Description = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Path.GetFileNameWithoutExtension(dialog.FileName));
  327. form.AppliesTo = appliesto;
  328. new Client<DigitalForm>().Save(form, $"Imported from {dialog.FileName}");
  329. progress.Report("Importing Data");
  330. DFLayout data;
  331. var variables = new List<DigitalFormVariable>();
  332. var layout = new DigitalFormLayout();
  333. layout.Form.ID = form.ID;
  334. layout.Code = form.Code;
  335. layout.Description = form.Description;
  336. using (var fs = new FileStream(dialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
  337. {
  338. var spreadsheet = new Spreadsheet(fs);
  339. data = DigitalFormUtils.LoadLayout(spreadsheet);
  340. layout.Layout = data.SaveLayout();
  341. }
  342. new Client<DigitalFormLayout>().Save(layout, $"Imported from {dialog.FileName}");
  343. progress.Report("Setting Up Variables");
  344. String group = "";
  345. foreach (var element in data.Elements)
  346. {
  347. if (element is DFLayoutHeader header)
  348. {
  349. group = header.Header;
  350. }
  351. else if (element is DFLayoutField field)
  352. {
  353. var variable = new DigitalFormVariable();
  354. variable.Form.ID = form.ID;
  355. variable.SetFieldType(field.GetType());
  356. variable.SaveProperties(field.GetProperties());
  357. variable.Group = group;
  358. variable.Code = field.Name;
  359. variable.Description = field.Name;
  360. variables.Add(variable);
  361. }
  362. }
  363. if (variables.Any())
  364. new Client<DigitalFormVariable>().Save(variables, $"Imported from {dialog.FileName}");
  365. progress.Report("Creating Report");
  366. var model = DigitalFormUtils.GetDataModel(appliesto, variables);
  367. var template = DigitalFormUtils.GenerateReport(layout, model);
  368. var report = new ReportTemplate();
  369. report.Section = form.ID.ToString();
  370. report.DataModel = model.Name;
  371. report.Name = form.Description;
  372. report.RDL = template?.SaveToString();
  373. new Client<ReportTemplate>().Save(report, $"Imported from {dialog.FileName}");
  374. });
  375. MessageBox.Show($"[{code}] imported successully!");
  376. Refresh(false, true);
  377. return;
  378. }
  379. DigitalFormExportData? data;
  380. using(var stream = dialog.OpenFile())
  381. {
  382. data = Serialization.Deserialize<DigitalFormExportData>(stream);
  383. if (data is null)
  384. {
  385. MessageBox.Show("File corrupt");
  386. return;
  387. }
  388. }
  389. try
  390. {
  391. var form = data.ToForm();
  392. var layouts = data.Layouts.Select(x => x.ToLayout()).ToList();
  393. var variables = data.Variables.Select(x => x.ToVariable()).ToList();
  394. var documents = data.Documents.Select(x => x.ToDocument()).ToList();
  395. var formDocuments = new List<DigitalFormDocument>();
  396. foreach (var document in documents)
  397. {
  398. new Client<Document>().Save(document, "");
  399. var digitalFormDocument = new DigitalFormDocument();
  400. digitalFormDocument.DocumentLink.ID = document.ID;
  401. digitalFormDocument.DocumentLink.Synchronise(document);
  402. formDocuments.Add(digitalFormDocument);
  403. }
  404. if (EditItems(new DigitalForm[] { form }, (type) =>
  405. {
  406. var table = new CoreTable();
  407. table.LoadColumns(type);
  408. if(type == typeof(DigitalFormLayout))
  409. {
  410. table.LoadRows(layouts);
  411. }
  412. else if(type == typeof(DigitalFormVariable))
  413. {
  414. table.LoadRows(variables);
  415. }
  416. else if(type == typeof(DigitalFormDocument))
  417. {
  418. table.LoadRows(formDocuments);
  419. }
  420. return table;
  421. }))
  422. {
  423. Refresh(false, true);
  424. }
  425. /*new Client<DigitalForm>().Save(form, "Imported by user");
  426. foreach (var layout in layouts)
  427. {
  428. layout.Form.ID = form.ID;
  429. new Client<DigitalFormLayout>().Save(layout, "");
  430. }
  431. foreach (var variable in variables)
  432. {
  433. variable.Form.ID = form.ID;
  434. new Client<DigitalFormVariable>().Save(variable, "");
  435. }
  436. foreach (var document in documents)
  437. {
  438. new Client<Document>().Save(document, "");
  439. var digitalFormDocument = new DigitalFormDocument();
  440. digitalFormDocument.EntityLink.ID = form.ID;
  441. digitalFormDocument.DocumentLink.ID = document.ID;
  442. new Client<DigitalFormDocument>().Save(digitalFormDocument, "");
  443. }*/
  444. }
  445. catch(Exception e)
  446. {
  447. MessageBox.Show(e.Message);
  448. }
  449. }
  450. protected override void DoExport()
  451. {
  452. var rows = SelectedRows;
  453. if(rows.Length == 0)
  454. {
  455. MessageBox.Show("Please select a form to export.");
  456. return;
  457. }
  458. else if(rows.Length > 1)
  459. {
  460. MessageBox.Show("Please select only one form to export.");
  461. return;
  462. }
  463. var formID = rows[0].Get<DigitalForm, Guid>(x => x.ID);
  464. var results = Client.QueryMultiple(
  465. new KeyedQueryDef<DigitalForm>(
  466. new Filter<DigitalForm>(x => x.ID).IsEqualTo(formID),
  467. new Columns<DigitalForm>(x => x.Code)
  468. .Add(x => x.Description)
  469. .Add(x => x.AppliesTo)),
  470. new KeyedQueryDef<DigitalFormLayout>(
  471. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(formID),
  472. new Columns<DigitalFormLayout>(x => x.Code)
  473. .Add(x => x.Description)
  474. .Add(x => x.Type)
  475. .Add(x => x.Layout)),
  476. new KeyedQueryDef<DigitalFormVariable>(
  477. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(formID),
  478. new Columns<DigitalFormVariable>(x => x.Code)
  479. .Add(x => x.Description)
  480. .Add(x => x.VariableType)
  481. .Add(x => x.Parameters)
  482. .Add(x => x.Required)
  483. .Add(x => x.Secure)
  484. .Add(x => x.Retain)
  485. .Add(x => x.Hidden)
  486. .Add(x => x.Sequence)),
  487. new KeyedQueryDef<Document>(
  488. new Filter<Document>(x => x.ID).InQuery(
  489. new Filter<DigitalFormDocument>(x => x.EntityLink.ID).IsEqualTo(formID),
  490. x => x.DocumentLink.ID),
  491. new Columns<Document>(x => x.FileName)
  492. .Add(x => x.Data)));
  493. var data = new DigitalFormExportData(results.Get<DigitalForm>().Rows.First().ToObject<DigitalForm>())
  494. {
  495. Layouts = results.Get<DigitalFormLayout>().ToObjects<DigitalFormLayout>().Select(x => new DigitalFormExportData.LayoutData(x)).ToList(),
  496. Variables = results.Get<DigitalFormVariable>().ToObjects<DigitalFormVariable>().Select(x => new DigitalFormExportData.VariableData(x)).ToList(),
  497. Documents = results.Get<Document>().ToObjects<Document>().Select(x => new DigitalFormExportData.DocumentData(x)).ToList()
  498. };
  499. var filename = rows[0].Get<DigitalForm, string>(x => x.Description);
  500. if (string.IsNullOrWhiteSpace(filename))
  501. filename = rows[0].Get<DigitalForm, string>(x => x.Code);
  502. if (string.IsNullOrWhiteSpace(filename))
  503. filename = "form";
  504. var dialog = new SaveFileDialog
  505. {
  506. Filter = ExportFileFilter,
  507. FileName = $"{filename}.prs-form"
  508. };
  509. if(dialog.ShowDialog() == true)
  510. {
  511. using var stream = dialog.OpenFile();
  512. Serialization.Serialize(data, stream);
  513. }
  514. }
  515. protected override void DoValidate(DigitalForm[] items, List<string> errors)
  516. {
  517. base.DoValidate(items, errors);
  518. if (items.Any(x => string.IsNullOrWhiteSpace(x.AppliesTo)))
  519. errors.Add("[Applies To] must not be blank!");
  520. }
  521. }
  522. }