using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using FastReport; using InABox.Clients; using InABox.Core; using InABox.Core.Reports; using InABox.Scripting; using InABox.Wpf; using InABox.WPF; using Microsoft.Win32; using NPOI.HPSF; namespace InABox.DynamicGrid { public class DigitalFormExportData { public string Code { get; set; } public string Description { get; set; } public string AppliesTo { get; set; } public DigitalFormExportData() { } public DigitalFormExportData(DigitalForm form) { Code = form.Code; Description = form.Description; AppliesTo = form.AppliesTo; } public List Layouts { get; set; } public List Variables { get; set; } public List Documents { get; set; } public DigitalForm ToForm() => new DigitalForm { Code = Code, Description = Description, AppliesTo = AppliesTo }; public class LayoutData { public string Code { get; set; } public string Description { get; set; } public DFLayoutType Type { get; set; } public string Layout { get; set; } public LayoutData() { } public LayoutData(DigitalFormLayout layout) { Code = layout.Code; Description = layout.Description; Type = layout.Type; Layout = layout.Layout; } public DigitalFormLayout ToLayout() => new DigitalFormLayout { Code = Code, Description = Description, Type = Type, Layout = Layout }; } public class VariableData { public string Code { get; set; } public string Description { get; set; } public string VariableType { get; set; } public string Parameters { get; set; } public bool Required { get; set; } public bool Secure { get; set; } public bool Retain { get; set; } public bool Hidden { get; set; } public long Sequence { get; set; } public VariableData() { } public VariableData(DigitalFormVariable variable) { Code = variable.Code; Description = variable.Description; VariableType = variable.VariableType; Parameters = variable.Parameters; Required = variable.Required; Secure = variable.Secure; Retain = variable.Retain; Hidden = variable.Hidden; Sequence = variable.Sequence; } public DigitalFormVariable ToVariable() => new DigitalFormVariable { Code = Code, Description = Description, VariableType = VariableType, Parameters = Parameters, Required = Required, Secure = Secure, Retain = Retain, Hidden = Hidden, Sequence = Sequence }; } public class DocumentData { public string FileName { get; set; } public byte[] Data { get; set; } public Guid ID { get; set; } public DocumentData() { } public DocumentData(Document document) { FileName = document.FileName; Data = document.Data; ID = document.ID; } public Document ToDocument() => new Document { FileName = FileName, Data = Data, TimeStamp = DateTime.Now, ID = ID }; } } public class DigitalFormGrid : DynamicDataGrid { private bool _showall; private Button CopyForm = null!; // Late-initialised protected override void Init() { base.Init(); AddButton("Show All", null, ShowAllClick); // TODO: Add back in //ActionColumns.Add(new DynamicImageColumn(ReportImage, ReportClick)); AddButton("Groups", null, EditGroupsClick); CopyForm = AddButton("Duplicate", InABox.Wpf.Resources.copy.AsBitmapImage(), CopyForm_Click); CopyForm.IsEnabled = false; if (!Security.CanEdit()) { CopyForm.Visibility = Visibility.Collapsed; } OnCustomiseEditor += DigitalFormGrid_OnCustomiseEditor; } protected override void DoReconfigure(DynamicGridOptions options) { base.DoReconfigure(options); options.ImportData = true; options.ExportData = true; options.FilterRows = true; options.SelectColumns = true; } protected override void SelectItems(CoreRow[]? rows) { base.SelectItems(rows); CopyForm.IsEnabled = rows is not null && rows.Length == 1; } private bool CopyForm_Click(Button btn, CoreRow[] rows) { if(rows.Length != 1) { MessageWindow.ShowMessage("Please select one form to copy.", "Invalid selection."); return false; } var form = rows[0].ToObject(); Client.EnsureColumns(form, Columns.None().Add(x => x.Description) .Add(x => x.AppliesTo) .Add(x => x.Secure) .Add(x => x.Final) .Add(x => x.Group.ID)); var newForm = new DigitalForm(); newForm.Description = form.Description; newForm.AppliesTo = form.AppliesTo; newForm.Secure = form.Secure; newForm.Final = form.Final; newForm.Group.ID = form.Group.ID; var children = Client.QueryMultiple( new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(form.ID), Columns.None().Add(x => x.Code) .Add(x => x.Description) .Add(x => x.Type) .Add(x => x.Layout) .Add(x => x.Active)), new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(form.ID), Columns.None().Add(x => x.Code) .Add(x => x.Description) .Add(x => x.VariableType) .Add(x => x.Group) .Add(x => x.Parameters) .Add(x => x.Required) .Add(x => x.Secure) .Add(x => x.Retain) .Add(x => x.Hidden) .Add(x => x.Sequence)), new KeyedQueryDef( new Filter(x => x.Section).IsEqualTo(form.ID.ToString()), Columns.None().Add(x => x.Section) .Add(x=>x.Name) .Add(x=>x.Script) .Add(x=>x.Visible) .Add(x=>x.AllRecords) .Add(x=>x.DataModel) .Add(x=>x.PrinterName) .Add(x=>x.SelectedRecords) .Add(x=>x.RDL) .Add(x=>x.Section)), new KeyedQueryDef( new Filter(x => x.EntityLink.ID).IsEqualTo(form.ID), Columns.None().Add(x => x.Type) .Add(x => x.DocumentLink.ID) .Add(x => x.Superceded) .Add(x => x.Thumbnail) .Add(x => x.Notes))); if (EditItems(new[] { newForm }, type => { return children.GetOrDefault(type.Name); })) { return true; } else { return false; } } private bool EditGroupsClick(Button arg1, CoreRow[] arg2) { new MasterList(typeof(DigitalFormGroup)).ShowDialog(); return false; } private BitmapImage? ReportImage(CoreRow arg) { return arg != null ? Wpf.Resources.printer.AsBitmapImage() : null; } /*private bool ReportClick(CoreRow arg) { if (arg == null) return false; var typename = arg.Get(c => c.AppliesTo); var formid = arg.Get(c => c.ID); // Get Applies To /*Type type = CoreUtils.GetEntity("Comal.Classes."+typename); CoreTable entity = new CoreTable(); entity.LoadColumns(type); // Get Form Details CoreTable form = new CoreTable(); form.Columns.Add(new CoreColumn() { ColumnName = "ID", DataType = typeof(Guid) }); form.Columns.Add(new CoreColumn() { ColumnName = "Parent.ID", DataType = typeof(Guid) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.Form.Description, "."), DataType = typeof(String) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.FormCompletedBy.UserID, "."), DataType = typeof(String) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.FormCompleted, "."), DataType = typeof(String) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.Location.Address, "."), DataType = typeof(String) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.Location.Latitude, "."), DataType = typeof(String) }); form.Columns.Add(new CoreColumn() { ColumnName = CoreUtils.GetFullPropertyName(x => x.Location.Longitude, "."), DataType = typeof(String) }); var variables = new Client().Query(new Filter(x => x.Form.ID).IsEqualTo(formid)); foreach (var row in variables.Rows) { form.Columns.Add( new CoreColumn() { ColumnName = row.Get(c => c.Code), DataType = DigitalFormVariable.DataType(row.Get(c => c.VariableType)) } ); }* // Create DataModel //DigitalFormReportDataModel model = new DigitalFormReportDataModel(form,entity,typename); AutoDataModel model = new AutoDataModel(new Filter(x => x.ID).IsEqualTo(formid)); // Load Template var template = new Client() .Load(new Filter(x => x.Section).IsEqualTo("DigitalForms").And(x => x.Name).IsEqualTo(formid.ToString())) .FirstOrDefault(); if (template == null) { template = new ReportTemplate { Section = "DigitalForms", Name = formid.ToString(), Visible = false }; new Client().Save(template, ""); } ReportUtils.DesignReport(template, model); // Preview Report return false; }*/ private bool ShowAllClick(Button arg1, CoreRow[] arg2) { _showall = !_showall; UpdateButton(arg1, null, _showall ? "Hide Inactive" : "Show All"); return true; } protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) { if (!_showall) criteria.Add(new Filter(x => x.Active).IsEqualTo(true)); base.Reload(criteria, columns, ref sort, action); } public override DynamicEditorPages LoadEditorPages(DigitalForm item) { var pages = base.LoadEditorPages(item); pages.Add(new DigitalFormReportGrid()); return pages; } private DynamicVariableGrid? GetVariableGrid(IDynamicEditorForm sender) => sender.Pages?.FirstOrDefault(x => x is DynamicVariableGrid) as DynamicVariableGrid; private List GetVariables(IDynamicEditorForm sender) => GetVariableGrid(sender)?.Items.ToList() ?? new List(); // Using the event because it also has the editor form 'sender'. private void DigitalFormGrid_OnCustomiseEditor(IDynamicEditorForm sender, DigitalForm[]? items, DynamicGridColumn column, BaseEditor editor) { if(editor is ExpressionEditor exp && ( new Column(x => x.DescriptionExpression).IsEqualTo(column.ColumnName) || new Column(x => x.ExportExpression).IsEqualTo(column.ColumnName))) { exp.OnGetVariables += () => { var variables = new List(); foreach (var variable in GetVariables(sender)) { foreach (var col in variable.GetVariableColumns()) variables.Add($"Data.{col.ColumnName}"); } var appliesTo = items?.Select(x => x.AppliesTo).Distinct().SingleOrDefault(); if (!appliesTo.IsNullOrWhiteSpace() && DFUtils.GetFormInstanceType(appliesTo) is Type instanceType) { foreach(var property in DatabaseSchema.Properties(instanceType).Where(x => !x.Name.StartsWith("Parent"))) variables.Add($"Form.{property.Name}"); } if (!appliesTo.IsNullOrWhiteSpace() && DFUtils.FormEntityType(appliesTo) is Type entityType) { foreach(var property in DatabaseSchema.Properties(entityType)) variables.Add($"{entityType.EntityName().Split('.').Last()}.{property.Name}"); } variables.Sort(); return variables; }; } } public override bool EditItems(DigitalForm[] items, Func? PageDataHandler = null, bool PreloadPages = false) { // Need to do this to make sure that the variables are available to the layouts (and vice versa?) return base.EditItems(items, PageDataHandler, true); } private const string ExportFileFilter = "Excel Files (*.xls, *xlsx)|*.xls;*.xlsx|Digital Forms (*.prs-form)|*.prs-form"; protected override void DoImport() { var dialog = new OpenFileDialog { Filter = ExportFileFilter }; if (dialog.ShowDialog() != true) return; String extension = Path.GetExtension(dialog.FileName) ?? ""; if (extension.ToLower().Equals(".xls") || extension.ToLower().Equals(".xlsx")) { String appliesto = ""; String code = ""; var lookups = new DigitalFormCategoryLookups(null).Lookups(); if (!DictionaryEdit.Execute(lookups, ref appliesto, "Applies To", "Select Form Type") || String.IsNullOrWhiteSpace(appliesto)) return; Progress.ShowModal("Creating Form", (progress) => { var codes = new Client().Query( null, Columns.None().Add(x => x.Code), null ).Rows.Select(r => r.Get(c => c.Code)).ToArray(); int i = 1; code = Path.GetFileNameWithoutExtension(dialog.FileName).ToUpper(); while (codes.Contains(code)) code = $"{Path.GetFileNameWithoutExtension(dialog.FileName).ToUpper()} ({i++})"; DigitalForm form = new DigitalForm(); form.Code = code; form.Description = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Path.GetFileNameWithoutExtension(dialog.FileName)); form.AppliesTo = appliesto; new Client().Save(form, $"Imported from {dialog.FileName}"); progress.Report("Importing Data"); DFLayout data; var variables = new List(); var layout = new DigitalFormLayout(); layout.Form.ID = form.ID; layout.Code = form.Code; layout.Description = form.Description; using (var fs = new FileStream(dialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { var spreadsheet = new Spreadsheet(fs); data = DigitalFormUtils.LoadLayout(spreadsheet); layout.Layout = data.SaveLayout(); } new Client().Save(layout, $"Imported from {dialog.FileName}"); progress.Report("Setting Up Variables"); String group = ""; foreach (var element in data.Elements) { if (element is DFLayoutHeader header) { group = header.Header; } else if (element is DFLayoutField field) { var variable = new DigitalFormVariable(); variable.Form.ID = form.ID; variable.SetFieldType(field.GetType()); variable.SaveProperties(field.GetProperties()); variable.Group = group; variable.Code = field.Name; variable.Description = field.Name; variables.Add(variable); } } if (variables.Any()) new Client().Save(variables, $"Imported from {dialog.FileName}"); progress.Report("Creating Report"); var model = DigitalFormUtils.GetDataModel(appliesto, variables); var template = DigitalFormUtils.GenerateReport(layout, model); var report = new ReportTemplate(); report.Section = form.ID.ToString(); report.DataModel = model.Name; report.Name = form.Description; report.RDL = template?.SaveToString(); new Client().Save(report, $"Imported from {dialog.FileName}"); }); MessageBox.Show($"[{code}] imported successully!"); Refresh(false, true); return; } DigitalFormExportData? data; using(var stream = dialog.OpenFile()) { data = Serialization.Deserialize(stream); if (data is null) { MessageBox.Show("File corrupt"); return; } } try { var form = data.ToForm(); var layouts = data.Layouts.Select(x => x.ToLayout()).ToList(); var variables = data.Variables.Select(x => x.ToVariable()).ToList(); var documents = data.Documents.Select(x => x.ToDocument()).ToList(); var formDocuments = new List(); foreach (var document in documents) { new Client().Save(document, ""); var digitalFormDocument = new DigitalFormDocument(); digitalFormDocument.DocumentLink.ID = document.ID; digitalFormDocument.DocumentLink.Synchronise(document); formDocuments.Add(digitalFormDocument); } if (EditItems(new DigitalForm[] { form }, (type) => { var table = new CoreTable(); table.LoadColumns(type); if(type == typeof(DigitalFormLayout)) { table.LoadRows(layouts); } else if(type == typeof(DigitalFormVariable)) { table.LoadRows(variables); } else if(type == typeof(DigitalFormDocument)) { table.LoadRows(formDocuments); } return table; })) { Refresh(false, true); } /*new Client().Save(form, "Imported by user"); foreach (var layout in layouts) { layout.Form.ID = form.ID; new Client().Save(layout, ""); } foreach (var variable in variables) { variable.Form.ID = form.ID; new Client().Save(variable, ""); } foreach (var document in documents) { new Client().Save(document, ""); var digitalFormDocument = new DigitalFormDocument(); digitalFormDocument.EntityLink.ID = form.ID; digitalFormDocument.DocumentLink.ID = document.ID; new Client().Save(digitalFormDocument, ""); }*/ } catch(Exception e) { MessageBox.Show(e.Message); } } protected override void DoExport() { var rows = SelectedRows; if(rows.Length == 0) { MessageBox.Show("Please select a form to export."); return; } else if(rows.Length > 1) { MessageBox.Show("Please select only one form to export."); return; } var formID = rows[0].Get(x => x.ID); var results = Client.QueryMultiple( new KeyedQueryDef( new Filter(x => x.ID).IsEqualTo(formID), Columns.None().Add(x => x.Code) .Add(x => x.Description) .Add(x => x.AppliesTo)), new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(formID), Columns.None().Add(x => x.Code) .Add(x => x.Description) .Add(x => x.Type) .Add(x => x.Layout)), new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(formID), Columns.None().Add(x => x.Code) .Add(x => x.Description) .Add(x => x.VariableType) .Add(x => x.Parameters) .Add(x => x.Required) .Add(x => x.Secure) .Add(x => x.Retain) .Add(x => x.Hidden) .Add(x => x.Sequence)), new KeyedQueryDef( new Filter(x => x.ID).InQuery( new Filter(x => x.EntityLink.ID).IsEqualTo(formID), x => x.DocumentLink.ID), Columns.None().Add(x => x.FileName) .Add(x => x.Data))); var data = new DigitalFormExportData(results.Get().Rows.First().ToObject()) { Layouts = results.Get().ToObjects().Select(x => new DigitalFormExportData.LayoutData(x)).ToList(), Variables = results.Get().ToObjects().Select(x => new DigitalFormExportData.VariableData(x)).ToList(), Documents = results.Get().ToObjects().Select(x => new DigitalFormExportData.DocumentData(x)).ToList() }; var filename = rows[0].Get(x => x.Description); if (string.IsNullOrWhiteSpace(filename)) filename = rows[0].Get(x => x.Code); if (string.IsNullOrWhiteSpace(filename)) filename = "form"; var dialog = new SaveFileDialog { Filter = ExportFileFilter, FileName = $"{filename}.prs-form" }; if(dialog.ShowDialog() == true) { using var stream = dialog.OpenFile(); Serialization.Serialize(data, stream); } } protected override void DoValidate(DigitalForm[] items, List errors) { base.DoValidate(items, errors); if (items.Any(x => string.IsNullOrWhiteSpace(x.AppliesTo))) errors.Add("[Applies To] must not be blank!"); } } }