Browse Source

Merge remote-tracking branch 'origin/kenric' into frank

frogsoftware 1 year ago
parent
commit
29dbadd5a3

+ 1 - 1
InABox.Core/CoreUtils.cs

@@ -2612,7 +2612,7 @@ namespace InABox.Core
         #region String Utilities
 
         /// <summary>
-        /// Check if <paramref name="s"/> is <see cref="string.IsNullOrWhiteSpace(string)"/>.
+        /// Check if <paramref name="s"/> <see cref="string.IsNullOrWhiteSpace(string)"/>.
         /// If it is empty, returns <paramref name="def"/>, otherwise, returns <paramref name="s"/>.
         /// </summary>
         /// <remarks>

+ 17 - 0
InABox.Core/DigitalForms/DFUtils.cs

@@ -228,5 +228,22 @@ namespace InABox.Core
                 x => string.Equals(x.Name, form.AppliesTo)
             ).FirstOrDefault();
         }
+
+        public static Type FormEntityType(Type TForm)
+        {
+            var formInstanceType = TForm.GetInterfaceDefinition(typeof(IDigitalFormInstance<>))
+                ?? throw new Exception("Form does not implement IDigitalFormInstance<>");
+            var linkType = formInstanceType.GenericTypeArguments[0];
+            var linkInterface = linkType.GetInterfaceDefinition(typeof(IEntityLink<>));
+            return linkInterface!.GenericTypeArguments[0];
+        }
+
+        /*public static IEntityLink GetParentLink(IDigitalFormInstance formInstance)
+        {
+
+            var parentlink = CoreUtils.HasProperty(formInstance.GetType(), "Parent")
+                ? CoreUtils.GetPropertyValue(formInstance, "Parent") as IEntityLink
+                : null;
+        }*/
     }
 }

+ 5 - 3
InABox.Core/DigitalForms/Forms/EntityForm.cs

@@ -19,13 +19,13 @@ namespace InABox.Core
         where TParentLink : IEntityLink<TParent>, new()
     {
 
-        public Expression<Func<TThis, String>> AutoIncrementField() => x => x.Number;
+        public Expression<Func<TThis, string>> AutoIncrementField() => x => x.Number;
 
-        public abstract String AutoIncrementPrefix();
+        public abstract string AutoIncrementPrefix();
 
         public virtual string AutoIncrementFormat() => "{0:D6}";
         
-        public Filter<TThis> AutoIncrementFilter() => null;
+        public Filter<TThis>? AutoIncrementFilter() => null;
         
         [EditorSequence(1)]
         [CodeEditor(Editable = Editable.Disabled)]
@@ -108,6 +108,8 @@ namespace InABox.Core
             return Parent.ID;
         }
 
+        public Type ParentType() => typeof(TParent);
+
         [DurationEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
         public TimeSpan FormOpen { get; set; } = TimeSpan.Zero;
 

+ 14 - 1
InABox.Core/DigitalForms/Forms/IDigitalFormInstance.cs

@@ -39,7 +39,11 @@ namespace InABox.Core
         
         IDigitalFormDataModel CreateDataModel(Entity? parent = null);
 
+        IEntityLink Parent { get; set; }
+
         Guid ParentID();
+
+        Type ParentType();
     }
 
     public interface IDigitalFormInstance : ICoreDigitalFormInstance
@@ -48,6 +52,15 @@ namespace InABox.Core
 
     public interface IDigitalFormInstance<TEntityLink> : IDigitalFormInstance where TEntityLink : IEntityLink
     {
-        TEntityLink Parent { get; set; }
+        new TEntityLink Parent { get; set; }
+
+        IEntityLink ICoreDigitalFormInstance.Parent
+        {
+            get => Parent;
+            set
+            {
+                Parent = (TEntityLink)value;
+            }
+        }
     }
 }

+ 11 - 5
InABox.Core/ILookupDefinition.cs

@@ -375,6 +375,12 @@ namespace InABox.Core
             return DoInvoke(TLookup, typeof(TEntity), items, typeof(Filter<>), "DefineFilter") as IFilter;
         }
 
+        public static Filter<TLookup>? DefineFilter<TLookup>(Type TEntity, IEnumerable items)
+            where TLookup : Entity
+        {
+            return DefineFilter(typeof(TLookup), TEntity, items) as Filter<TLookup>;
+        }
+
         public static Filter<TLookup>? DefineFilter<TEntity, TLookup>(TEntity[] items) where TEntity : Entity where TLookup : Entity
         {
             return DefineFilter(items, typeof(TLookup)) as Filter<TLookup>;
@@ -400,10 +406,10 @@ namespace InABox.Core
             return (DefineColumns(typeof(TLookup)) as Columns<TLookup>)!;
         }
 
-        public static IColumns DefineFilterColumns(Type TLookup, Type TEntity, IEnumerable items)
+        public static IColumns DefineFilterColumns(Type TLookup, Type TEntity)
         {
             var result = DoInvoke(TLookup, TEntity, typeof(Columns<>).MakeGenericType(TEntity), "DefineFilterColumns") as IColumns;
-            result ??= Columns.Create(TLookup).DefaultColumns();
+            result ??= Columns.Create(TEntity).DefaultColumns();
             return result;
         }
 
@@ -412,14 +418,14 @@ namespace InABox.Core
             var result = DoInvoke(TLookup, typeof(TEntity), typeof(Columns<>).MakeGenericType(typeof(TEntity)), "DefineFilterColumns") as IColumns;
             if (result == null)
             {
-                result = Columns.Create(TLookup);
+                result = Columns.Create(typeof(TEntity));
             }
             return result;
         }
 
-        public static Columns<TLookup> DefineFilterColumns<TEntity, TLookup>() where TEntity : Entity where TLookup : Entity
+        public static Columns<TEntity> DefineFilterColumns<TEntity, TLookup>() where TEntity : Entity where TLookup : Entity
         {
-            return DefineFilterColumns<TEntity>(typeof(TLookup)) as Columns<TLookup>;
+            return DefineFilterColumns<TEntity>(typeof(TLookup)) as Columns<TEntity>;
         }
 
         #endregion

+ 5 - 1
inabox.wpf/DigitalForms/DigitalFormReportGrid.cs

@@ -14,6 +14,7 @@ using FastReport.Table;
 using FastReport.Utils;
 using Border = System.Windows.Controls.Border;
 using Size = System.Windows.Size;
+using netDxf.Objects;
 
 namespace InABox.DynamicGrid
 {
@@ -212,7 +213,10 @@ namespace InABox.DynamicGrid
         protected override ReportTemplate CreateItem()
         {
             var item = base.CreateItem();
-            if(Form.ID != Guid.Empty)
+            var model = DigitalFormUtils.GetDataModel(Form.AppliesTo, GetVariables());
+            item.DataModel = model.Name;
+            
+            if (Form.ID != Guid.Empty)
             {
                 item.Section = Form.ID.ToString();
             }

+ 31 - 6
inabox.wpf/DigitalForms/DigitalFormUtils.cs

@@ -285,6 +285,22 @@ namespace InABox.DynamicGrid
         #endregion
         
         #region Report Generator
+
+        private static string ElementName(HashSet<string> names, string name)
+        {
+            int i = 0;
+            if(names.Contains(name))
+            {
+                string newName;
+                do
+                {
+                    newName = $"{name}{i}";
+                    ++i;
+                } while (names.Contains(newName));
+                name = newName;
+            }
+            return name;
+        }
         
         public static Report? GenerateReport(DigitalFormLayout layout, DataModel model)
         {
@@ -306,16 +322,21 @@ namespace InABox.DynamicGrid
 
             var formData = report.GetDataSource("Form_Data");
 
-            var band = new DataBand();
-            band.Name = "Data1";
-            band.Height = Units.Millimeters * (page.PaperHeight - (page.TopMargin + page.BottomMargin));
-            band.Width = Units.Millimeters * (page.PaperWidth - (page.LeftMargin + page.RightMargin));
-            band.PrintIfDatasourceEmpty = true;
-            band.DataSource = formData;
+            var band = new DataBand
+            {
+                Name = "Data1",
+                Height = Units.Millimeters * (page.PaperHeight - (page.TopMargin + page.BottomMargin)),
+                Width = Units.Millimeters * (page.PaperWidth - (page.LeftMargin + page.RightMargin)),
+                PrintIfDatasourceEmpty = true,
+                DataSource = formData
+            };
             page.AddChild(band);
 
+            var elementNames = new HashSet<string>();
+
             var table = new TableObject()
             {
+                Name = "FormTable",
                 ColumnCount = dfLayout.ColumnWidths.Count,
                 RowCount = dfLayout.RowHeights.Count
             };
@@ -335,6 +356,8 @@ namespace InABox.DynamicGrid
                     {
                         var manualHeight = 0.0f;
 
+                        cell.Name = ElementName(elementNames, $"Cell_{new string(field.Name.Where(c => !Char.IsWhiteSpace(c)).ToArray())}");
+
                         var dataColumn = $"Form_Data.{field.Name}";
                         if(field is DFLayoutEmbeddedImage || field is DFLayoutSignaturePad)
                         {
@@ -389,10 +412,12 @@ namespace InABox.DynamicGrid
                             label.Style.BackgroundColour = Color.WhiteSmoke;
                         }
                         cell.Text = label.Description;
+                        cell.Name = ElementName(elementNames, "Label_" + element.Row + "_" + element.Column);
                         ApplyStyle(cell, label.Style);
                     }
                     else if (element is DFLayoutHeader header)
                     {
+                        cell.Name = ElementName(elementNames, "Header_" + element.Row + "_" + element.Column);
                         cell.Text = header.Header;
                         ApplyStyle(cell, header.Style);
                     }

+ 4 - 1
inabox.wpf/DynamicGrid/Editors/DocumentEditor/DocumentConfirm.xaml.cs

@@ -6,6 +6,9 @@ using System.IO;
 using System.Reactive;
 using System.Windows;
 using InABox.WPF;
+using InABox.Clients;
+using System.Linq;
+using System.Diagnostics.CodeAnalysis;
 
 namespace InABox.DynamicGrid
 {
@@ -68,7 +71,7 @@ namespace InABox.DynamicGrid
 
         public static Document? CheckDocument(Document newDocument, Func<string, Document?>? findDocument, out bool shouldSave)
         {
-            Document existing = null;
+            Document? existing = null;
             
             using (new WaitCursor())
                 existing = findDocument?.Invoke(newDocument.FileName);

+ 35 - 13
inabox.wpf/DynamicGrid/MultiSelectDialog.cs

@@ -2,6 +2,7 @@
 using System.ComponentModel;
 using System.Linq;
 using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Forms;
@@ -112,27 +113,41 @@ namespace InABox.DynamicGrid
             CancelButton.SetValue(Grid.ColumnProperty, 3);
             grid.Children.Add(CancelButton);
         }
+        public bool ShowDialog(string? column = null, string? value = null, FilterType filtertype = FilterType.Contains) =>
+            ShowDialogInternal(null, column, value, filtertype);
+        public bool ShowDialog(string title) =>
+            ShowDialogInternal(title, null, null, default);
 
-        public bool ShowDialog(String? column = null, String? value = null, FilterType filtertype = FilterType.Contains)
+        private bool ShowDialogInternal(string? title, string? column, string? value, FilterType filtertype)
         {
-            window = new ThemableWindow { Title = "Select Items", WindowStyle = WindowStyle.SingleBorderWindow };
-            window.Content = grid;
+            window = new ThemableWindow
+            {
+                Title = title ?? "Select Items",
+                WindowStyle = WindowStyle.SingleBorderWindow,
+                Content = grid
+            };
             datagrid.Refresh(true, true);
-            if (!String.IsNullOrEmpty(column) && !String.IsNullOrEmpty(value))
+            if (!column.IsNullOrWhiteSpace() && !value.IsNullOrWhiteSpace())
                 datagrid.AddVisualFilter(column, value, filtertype);
             if (window.ShowDialog() == true)
                 return true;
             return false;
         }
 
+        private Window GetWindow([CallerMemberName] string methodName = "")
+        {
+            return window ?? throw new Exception($"Must call ShowDialog() before {methodName}()");
+        }
+
         public Guid[] IDs()
         {
-            if (window?.DialogResult == true)
+            var window = GetWindow();
+            if (window.DialogResult == true)
             {
                 if (datagrid?.Data != null && datagrid.SelectedRows.Any())
                     return datagrid.SelectedRows.Select(r => r.Get<T, Guid>(x => x.ID)).ToArray();
             }
-            else if (window?.DialogResult == false)
+            else if (window.DialogResult == false)
                 return new Guid[] { Guid.Empty };
 
             return Array.Empty<Guid>();
@@ -140,12 +155,17 @@ namespace InABox.DynamicGrid
 
         public CoreTable Data()
         {
+            var window = GetWindow();
+
             var result = new CoreTable();
             result.Columns.Add(new CoreColumn { ColumnName = "ID", DataType = typeof(Guid) });
-            foreach (var column in _columns.Items)
-                result.Columns.Add(new CoreColumn { ColumnName = column.Property, DataType = column.Type });
+            if(_columns is not null)
+            {
+                foreach (var column in _columns.Items)
+                    result.Columns.Add(new CoreColumn { ColumnName = column.Property, DataType = column.Type });
+            }
 
-            if (window?.DialogResult == true)
+            if (window.DialogResult == true)
             {
 
                 if (datagrid?.Data != null && datagrid.SelectedRows.Any())
@@ -160,7 +180,7 @@ namespace InABox.DynamicGrid
                         result.Rows.Add(row);
                     }
             }
-            else if (window?.DialogResult == false)
+            else if (window.DialogResult == false)
             {
                 var row = result.NewRow(true);
                 result.Rows.Add(row);
@@ -171,7 +191,9 @@ namespace InABox.DynamicGrid
         
         public T[] Items(Columns<T>? columns = null)
         {
-            if (window?.DialogResult == true)
+            var window = GetWindow();
+
+            if (window.DialogResult == true)
             {
                 if (datagrid.Data != null && datagrid.SelectedRows.Any())
                 {
@@ -186,7 +208,7 @@ namespace InABox.DynamicGrid
                     return items.ToArray();
                 }
             }
-            else if (window?.DialogResult == false)
+            else if (window.DialogResult == false)
                 return new T[] { new T() };
 
             return Array.Empty<T>();
@@ -206,7 +228,7 @@ namespace InABox.DynamicGrid
 
         private void CancelButton_Click(object sender, RoutedEventArgs e)
         {
-            window.Close();
+            window!.Close();
         }
 
         private void OKButton_Click(object sender, RoutedEventArgs e)

+ 17 - 1
inabox.wpf/ProgressWindow/Progress.cs

@@ -96,6 +96,8 @@ namespace InABox.WPF
 
         public static void ShowModal(string message, Action<IProgress<string>> work)
         {
+            Exception? exception = null;
+
             var progress = new ProgressForm
             {
                 DisplayImage = DisplayImage
@@ -111,13 +113,27 @@ namespace InABox.WPF
                     worker.CancelAsync();
                 };
 
-                worker.DoWork += (o, e) => work(update);
+                worker.DoWork += (o, e) =>
+                {
+                    try
+                    {
+                        work(update);
+                    }
+                    catch (Exception ex)
+                    {
+                        exception = ex;
+                    }
+                };
                 worker.RunWorkerCompleted +=
                     (o, e) => progress.Close();
                 worker.RunWorkerAsync();
             };
 
             progress.ShowDialog();
+            if(exception is not null)
+            {
+                throw exception;
+            }
         }
 
         public static void Show(string message)

+ 7 - 2
inabox.wpf/Reports/ReportUtils.cs

@@ -287,11 +287,16 @@ namespace InABox.Wpf.Reports
             return result;
         }
 
+        public static Filter<ReportTemplate> GetReportFilter(string sectionName, DataModel model)
+        {
+            return new Filter<ReportTemplate>(x => x.DataModel).IsEqualTo(model.Name)
+                    .And(x => x.Section).IsEqualTo(sectionName);
+        }
+
         public static IEnumerable<ReportTemplate> LoadReports(string sectionName, DataModel model)
         {
             return new Client<ReportTemplate>().Query(
-                new Filter<ReportTemplate>(x => x.DataModel).IsEqualTo(model.Name)
-                    .And(x => x.Section).IsEqualTo(sectionName),
+                GetReportFilter(sectionName, model),
                 null,
                 new SortOrder<ReportTemplate>(x => x.Name)).Rows.Select(x => x.ToObject<ReportTemplate>());
         }