using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.Core.Reports; using InABox.WPF; namespace InABox.DynamicGrid; public interface IDynamicOneToManyGrid : IDynamicEditorPage { void LoadItems(TMany[] items); } public class DynamicOneToManyGrid : DynamicGrid, IDynamicEditorPage, IDynamicOneToManyGrid where TOne : Entity, new() where TMany : Entity, IPersistent, IRemotable, new() { private readonly PropertyInfo property; protected DynamicGridCustomColumnsComponent ColumnsComponent; public DynamicOneToManyGrid() { Ready = false; Criteria = new Filters(); property = CoreUtils.GetOneToManyProperty(typeof(TMany), typeof(TOne)); AddHiddenColumn(property.Name + "." + nameof(IEntityLink.ID)); foreach (var col in LookupFactory.RequiredColumns()) HiddenColumns.Add(col); ColumnsComponent = new DynamicGridCustomColumnsComponent(this, GetTag()); DataComponent = new DynamicGridMemoryEntityDataComponent(this); base.DataComponent = DataComponent; } protected new DynamicGridMemoryEntityDataComponent DataComponent; protected override void Init() { } protected override void DoReconfigure(DynamicGridOptions options) { options.RecordCount = true; options.SelectColumns = true; if (Security.CanEdit() && !ReadOnly) { options.AddRows = true; options.EditRows = true; } if (Security.CanDelete() && !ReadOnly) options.DeleteRows = true; if (Security.CanImport() && !ReadOnly) options.ImportData = true; if (Security.CanExport()) options.ExportData = true; if (Security.CanMerge()) options.MultiSelect = true; } private static bool IsAutoEntity => typeof(TMany).HasAttribute(); protected Filters Criteria { get; } = new Filters(); public TOne Item { get; protected set; } public void LoadItems(TMany[] items) { DataComponent.LoadData(items); Refresh(false, true); } private static string GetTag() { return typeof(TOne).Name + "." + typeof(TMany).Name; } #region IDynamicEditorPage public DynamicEditorGrid EditorGrid { get; set; } public PageType PageType => PageType.Other; public bool Ready { get; set; } private bool _readOnly; public bool ReadOnly { get => _readOnly; set { if (_readOnly != value) { _readOnly = value; Reconfigure(); } } } public virtual void Load(object item, Func? PageDataHandler) { Reconfigure(); Item = (TOne)item; Refresh(true, false); var data = PageDataHandler?.Invoke(typeof(TMany)); if(data is not null) { DataComponent.LoadData(data); } { if (Item.ID == Guid.Empty) { data = new CoreTable(); data.LoadColumns(typeof(TMany)); DataComponent.LoadData(data); } else { var criteria = new Filters(); var exp = CoreUtils.GetPropertyExpression(property.Name + ".ID"); criteria.Add(new Filter(exp).IsEqualTo(Item.ID).And(exp).IsNotEqualTo(Guid.Empty)); criteria.AddRange(Criteria.Items); var sort = LookupFactory.DefineSort(); var columns = DynamicGridUtils.LoadEditorColumns(DataColumns()); DataComponent.LoadData(criteria.Combine(), columns, sort); } } Refresh(false, true); Ready = true; } public virtual void BeforeSave(object item) { // Don't need to do anything here } public virtual void AfterSave(object item) { foreach (var map in DataComponent.Items) { var prop = (property.GetValue(map) as IEntityLink)!; prop.ID = Item.ID; prop.Synchronise(Item); } DataComponent.SaveItems(); } public Size MinimumSize() { return new Size(400, 400); } public string Caption() { var caption = typeof(TMany).GetCustomAttribute(typeof(Caption)); if (caption != null) return ((Caption)caption).Text; var result = new Inflector.Inflector(new CultureInfo("en")).Pluralize(typeof(TMany).Name); return result; } public virtual int Order() { return int.MinValue; } #endregion #region DynamicGrid protected override bool CustomiseImportItem(TMany item) { var result = base.CustomiseImportItem(item); if (result) { var prop = (property.GetValue(item) as IEntityLink)!; prop.ID = Item.ID; prop.Synchronise(Item); } return result; } public override DynamicGridColumns GenerateColumns() { var cols = new DynamicGridColumns(); cols.AddRange(base.GenerateColumns().Where(x => !x.ColumnName.StartsWith(property.Name + "."))); return cols; } protected override DynamicGridColumns LoadColumns() { return ColumnsComponent.LoadColumns(); } protected override void SaveColumns(DynamicGridColumns columns) { ColumnsComponent.SaveColumns(columns); } protected override void LoadColumnsMenu(ContextMenu menu) { base.LoadColumnsMenu(menu); ColumnsComponent.LoadColumnsMenu(menu); } protected override DynamicGridSettings LoadSettings() { var tag = GetTag(); var user = Task.Run(() => new UserConfiguration(tag).Load()); user.Wait(); return user.Result; } protected override void SaveSettings(DynamicGridSettings settings) { var tag = GetTag(); new UserConfiguration(tag).Save(settings); } public override TMany CreateItem() { var result = new TMany(); var prop = (property.GetValue(result) as IEntityLink)!; prop.ID = Item.ID; prop.Synchronise(Item); return result; } protected override BaseEditor? GetEditor(object item, DynamicGridColumn column) { var type = CoreUtils.GetProperty(typeof(TMany), column.ColumnName).DeclaringType; if (type.GetInterfaces().Contains(typeof(IEntityLink)) && type.ContainsInheritedGenericType(typeof(TOne))) return new NullEditor(); return base.GetEditor(item, column); } public override DynamicEditorPages LoadEditorPages(TMany item) { return item.ID != Guid.Empty ? base.LoadEditorPages(item) : new DynamicEditorPages(); } #endregion }