using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Windows; using InABox.Clients; using InABox.Core; using InABox.WPF; namespace InABox.DynamicGrid { /// /// Interaction logic for FormDesigner.xaml /// public partial class DynamicFormEditWindow : DynamicFormWindow { public enum FormResult { None, Cancel, Save, Complete } public DynamicFormEditWindow() { InitializeComponent(); Grid.OnChanged += Grid_OnChanged; //Complete.IsEnabled = Security.IsAllowed(); } protected override DynamicFormDesignGrid Grid { get => Preview; } public FormMode Mode { get => Grid.Mode; private set => Grid.Mode = value; } public FormResult Result = FormResult.None; public IDigitalFormDataModel? DataModel { get => Grid.DataModel; set { Grid.DataModel = value; RefreshEnabled(); } } /// /// Gets or sets the values in the form; can only be accessed after . /// public Dictionary Values { get => Grid.SaveValues(); set { Grid.LoadValues(value); RefreshEnabled(); } } private bool IsReopening = false; private bool HasChanged = false; private bool HasUnsavedChanges => Grid.IsChanged || HasChanged || DataModel!.Instance.ID == Guid.Empty; private void RefreshEnabled() { var formInstance = DataModel!.Instance; var completed = formInstance.FormCompleted; CompletedDate.Content = !completed.IsEmpty() ? $"Completed {completed:d MMM yyyy} at {completed:hh:mm tt}" : "Not completed yet"; if (completed.IsEmpty() && DFUtils.CanEditForm(formInstance.GetType(), formInstance, DataModel.Entity)) { Mode = FormMode.Filling; } else { Mode = Security.IsAllowed() ? FormMode.Editing : FormMode.ReadOnly; } if (Mode == FormMode.Editing || Mode == FormMode.Filling || Mode == FormMode.Preview) { SaveForm.IsEnabled = HasUnsavedChanges; } else { SaveForm.IsEnabled = false; } if (!completed.IsEmpty() && Security.IsAllowed()) { CompleteForm.Content = "Re-open form"; CompleteForm.IsEnabled = true; IsReopening = true; } else { CompleteForm.Content = "Complete form"; CompleteForm.IsEnabled = Mode == FormMode.Filling && DataModel?.Instance.FormCompleted == DateTime.MinValue; IsReopening = false; } } private void Grid_OnChanged(DynamicFormDesignGrid sender, string fieldName) { if (Mode == FormMode.Editing || Mode == FormMode.Filling || Mode == FormMode.Preview) { SaveForm.IsEnabled = true; } } private void Cancel_Click(object sender, RoutedEventArgs e) { Result = FormResult.Cancel; DialogResult = false; } private void Complete() { if (!Grid.Validate(out var messages)) { MessageBox.Show(string.Join('\n', messages)); return; } if (MessageBox.Show("Are you sure you want to complete this form?", "Confirm Completion", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { Result = FormResult.Complete; DialogResult = true; } } private void Reopen() { HasChanged = true; DataModel!.Instance.FormCompleted = DateTime.MinValue; DataModel!.Instance.FormCompletedBy.Clear(); RefreshEnabled(); } private void CompleteForm_Click(object sender, RoutedEventArgs e) { if (IsReopening) Reopen(); else Complete(); } private void SaveForm_Click(object sender, RoutedEventArgs e) { if (DataModel?.Instance.FormCompleted.IsEmpty() == false && !Grid.Validate(out var messages)) { MessageBox.Show(string.Join('\n', messages)); return; } if (MessageBox.Show("Are you sure you want to save this form?", "Confirm Save", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { Result = FormResult.Save; DialogResult = true; } } public static Columns FormColumns() where TForm : IDigitalFormInstance { return (FormColumns(typeof(TForm)) as Columns)!; } public static IColumns FormColumns(Type TForm) { return Columns.Create(TForm) .Add(x => x.ID) .Add(x => x.FormCompleted) .Add(x => x.FormData) .Add(x => x.BlobData) .Add(x => x.Form.ID) .Add(x => x.Form.Description) .Add("Parent.ID"); } public static bool EditDigitalForm( IDigitalFormInstance formInstance, [NotNullWhen(true)] out IDigitalFormDataModel? dataModel, Entity? parent = null) { dataModel = null; DigitalFormLayout layout = null; DigitalFormVariable[] variables = null; Dictionary values = null; String error = ""; Progress.ShowModal("Loading Form", (progress) => { var formid = formInstance.Form.ID; values = DigitalForm.DeserializeFormData(formInstance); var results = Client.QueryMultiple( new KeyedQueryDef(new Filter(x => x.Form.ID).IsEqualTo(formid)), new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(formid) .And(x => x.Active).IsEqualTo(true) .And(x => x.Layout).IsNotEqualTo(""))); variables = results[nameof(DigitalFormVariable)].Rows.Select(x => x.ToObject()).ToArray(); var desktopLayout = results[nameof(DigitalFormLayout)] .Rows.FirstOrDefault(x => x.Get(x => x.Type) == DFLayoutType.Desktop) ?.ToObject(); layout = desktopLayout ?? results[nameof(DigitalFormLayout)].ToObjects().FirstOrDefault(); if (layout != null) { if (parent is null) { var parentlink = CoreUtils.HasProperty(formInstance.GetType(), "Parent") ? CoreUtils.GetPropertyValue(formInstance, "Parent") as IEntityLink : null; var parenttype = parentlink?.GetType().BaseType?.GetGenericArguments().FirstOrDefault(); if (parenttype != null && parentlink != null) { var parentid = parentlink.ID; var filter = Filter.Create(parenttype); filter.Expression = CoreUtils.GetMemberExpression(parenttype, "ID"); filter.Operator = Operator.IsEqualTo; filter.Value = parentid; var client = (Activator.CreateInstance(typeof(Client<>).MakeGenericType(parenttype)) as Client)!; parent = client.Query(filter, null, null).Rows.FirstOrDefault()?.ToObject(parenttype) as Entity; } if (parent == null) { Logger.Send(LogType.Error, "", $"Form parent is null; Form Type: {formInstance.GetType()}; Parent Type: {parenttype}; Form ID: {formInstance.ID}"); error = "An error occurred while loading the form: Form Entity is null"; } } } else error = "No layout found for form!"; }); if (!String.IsNullOrWhiteSpace(error)) { MessageBox.Show(error); return false; } var form = new DynamicFormEditWindow { Type = layout.Type, Title = string.Format("Viewing {0}", formInstance.Form.Description) //Completed = !formInstance.FormCompleted.IsEmpty() }; form.LoadLayout(layout, variables); try { dataModel = formInstance.CreateDataModel(parent); dataModel.OnModelSaved += (model) => { DFUtils.OnSave(formInstance.GetType(), formInstance, parent); }; form.DataModel = dataModel; } catch (Exception e) { Logger.Send(LogType.Error, ClientFactory.UserID, $"Error during Edit Form / CreateDataModel: {CoreUtils.FormatException(e)}"); } form.Initialize(); if (values is not null) form.Values = values; if (form.ShowDialog() == true) { if (form.Result == FormResult.Complete) { formInstance.FormCompleted = DateTime.Now; formInstance.FormCompletedBy.ID = ClientFactory.UserGuid; formInstance.FormCompletedBy.UserID = ClientFactory.UserID; /*formInstance.FormCompleted = form.Completed ? formInstance.FormCompleted.IsEmpty() ? DateTime.Now : formInstance.FormCompleted : DateTime.MinValue; formInstance.FormCompletedBy.ID = form.Completed ? !formInstance.FormCompletedBy.IsValid() ? ClientFactory.UserGuid : formInstance.FormCompletedBy.ID : Guid.Empty; formInstance.FormCompletedBy.UserID = form.Completed ? string.IsNullOrWhiteSpace(formInstance.FormCompletedBy.UserID) ? ClientFactory.UserID : formInstance.FormCompletedBy.UserID : "";*/ } DigitalForm.SerializeFormData(formInstance, variables, form.Values); } return form.Result == FormResult.Save || form.Result == FormResult.Complete; } public static bool EditDigitalForm(Guid formID, [NotNullWhen(true)] out IDigitalFormDataModel? dataModel) where TForm : Entity, IDigitalFormInstance, IRemotable, IPersistent, new() { var form = new Client() .Query( new Filter(x => x.ID).IsEqualTo(formID), FormColumns()) .Rows.FirstOrDefault()?.ToObject(); if(form is null) { throw new Exception($"{typeof(TForm)} {formID} does not exist"); } return EditDigitalForm(form, out dataModel); } private void DynamicFormWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if(DialogResult != true && HasUnsavedChanges) { if(MessageBox.Show("This form has unsaved changes. Do you wish to discard them?", "Discard Changes?", MessageBoxButton.YesNo) != MessageBoxResult.Yes) { e.Cancel = true; } } } } }