using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Reflection; 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 { List Items { get; } void LoadItems(TMany[] items); } public class DynamicOneToManyGrid : DynamicGrid, IDynamicEditorPage, IDynamicOneToManyGrid where TOne : Entity, new() where TMany : Entity, IPersistent, IRemotable, new() { private TMany[] MasterList = { }; private readonly PropertyInfo property; public PageType PageType => PageType.Other; public DynamicOneToManyGrid() { Ready = false; Items = new List(); Criteria = new Filters(); property = CoreUtils.GetOneToManyProperty(typeof(TMany), typeof(TOne)); Options.BeginUpdate(); Options.Add(DynamicGridOption.RecordCount) .Add(DynamicGridOption.SelectColumns); if (Security.CanEdit()) Options.Add(DynamicGridOption.AddRows).Add(DynamicGridOption.EditRows); if (Security.CanDelete()) Options.Add(DynamicGridOption.DeleteRows); if (Security.CanImport()) Options.Add(DynamicGridOption.ImportData); if (Security.CanExport()) Options.Add(DynamicGridOption.ExportData); if (Security.CanMerge()) Options.Add(DynamicGridOption.MultiSelect); Options.EndUpdate(); /*var t = typeof(TMany).BaseType; if (t != null && t.IsConstructedGenericType && t.GetGenericTypeDefinition() == typeof(EntityForm<,>)) { ActionColumns.Add(new DynamicImageColumn(QAEditImage, QAEditClick)); if (DynamicGridUtils.PreviewReport != null) ActionColumns.Add(new DynamicImageColumn(QAPrintImage, QAPrintClick)); HiddenColumns.Add(x => (x as IDigitalFormInstance).FormData); HiddenColumns.Add(x => (x as IDigitalFormInstance).FormCompleted); HiddenColumns.Add(x => (x as IDigitalFormInstance).FormCompletedBy.ID); HiddenColumns.Add(x => (x as IDigitalFormInstance).Form.ID); }*/ } protected Filters Criteria { get; } public TOne Item { get; protected set; } public bool Ready { get; set; } public DynamicEditorGrid EditorGrid { get; set; } 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; } public virtual void Load(object item, Func? PageDataHandler) { Item = (TOne)item; CoreTable? data = PageDataHandler?.Invoke(typeof(TMany)); if (data == null) { if (Item.ID == Guid.Empty) { data = new CoreTable(); data.LoadColumns(typeof(TMany)); } 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(); data = new Client().Query(criteria.Combine(), null, sort); } } MasterList = data.Rows.Select(x => x.ToObject()).ToArray(); Items = MasterList.ToList(); Refresh(true, true); Ready = true; } public void BeforeSave(object item) { // Don't need to do anything here } protected virtual void OnDeleteItem(TMany item) { new Client().Delete(item, typeof(TMany).Name + " Deleted by User"); } public void AfterSave(object item) { // First remove any deleted files foreach (var map in MasterList) if (!Items.Contains(map)) OnDeleteItem(map); foreach (var map in Items) { var prop = (property.GetValue(map) as IEntityLink)!; prop.ID = Item.ID; prop.Synchronise(Item); //if (map.IsChanged()) // new Client().Save(map, "Updated by User"); } new Client().Save(Items.Where(x => x.IsChanged()), "Updated by User"); } protected override CoreTable LoadImportKeys(string[] fields) { var result = base.LoadImportKeys(fields); result.LoadRows(MasterList); return result; } 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 Size MinimumSize() { return new Size(400, 400); } public List Items { get; private set; } public void LoadItems(TMany[] items) { Items.Clear(); Items.AddRange(items); Refresh(false, true); } protected override DynamicGridColumns LoadColumns() { var tag = typeof(TOne).Name + "." + typeof(TMany).Name; var global = Task.Run(() => new GlobalConfiguration(tag).Load()); var user = Task.Run(() => new UserConfiguration(tag).Load()); Task.WaitAll(global, user); var columns = user.Result.Any() ? user.Result : global.Result; if (columns.Count == 0) columns.AddRange(base.LoadColumns().Where(x => !x.ColumnName.StartsWith(property.Name))); return columns; } protected override void SaveColumns(DynamicGridColumns columns) { var tag = typeof(TOne).Name + "." + typeof(TMany).Name; new UserConfiguration(tag).Save(columns); } protected override TMany CreateItem() { var result = new TMany(); var prop = (IEntityLink)property.GetValue(result); prop.ID = Item.ID; return result; } protected override TMany LoadItem(CoreRow row) { return Items[_recordmap[row].Index]; } protected override TMany[] LoadItems(CoreRow[] rows) { var result = new List(); foreach (var row in rows) result.Add(LoadItem(row)); return result.ToArray(); } public override void SaveItem(TMany item) { if (!Items.Contains(item)) Items.Add(item); if (item is ISequenceable) Items = Items.AsQueryable().OrderBy(x => (x as ISequenceable).Sequence).ToList(); //var sort = LookupFactory.DefineSort(); //if (sort != null) // Items = Items.AsQueryable().SortBy(sort.Expression).ToList(); } protected override void DeleteItems(params CoreRow[] rows) { var items = rows.Select(LoadItem).ToList(); foreach(var item in items) { Items.Remove(item); } } protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) { //var exp = BaseObject.DefaultSortOrder().Expression; //Items = Items.AsQueryable().SortBy(exp).To var results = new CoreTable(); results.LoadColumns(typeof(TMany)); if (sort != null) { var exp = IQueryableExtensions.ToLambda(sort.Expression); var sorted = sort.Direction == SortDirection.Ascending ? Items.AsQueryable().OrderBy(exp) : Items.AsQueryable().OrderByDescending(exp); foreach (var then in sort.Thens) { var thexp = IQueryableExtensions.ToLambda(then.Expression); sorted = sort.Direction == SortDirection.Ascending ? sorted.ThenBy(exp) : sorted.ThenByDescending(exp); } Items = sorted.ToList(); } results.LoadRows(Items); //if (sort != null) // results.LoadRows(Items.AsQueryable().SortBy(sort.Expression)); //else // results.LoadRows(Items.OrderBy(x=>x.Sort)); action.Invoke(results, null); } 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); } //protected override void EditorValueChanged(object item, string name, object value, List changes) //{ // Entity entity = (Entity)item; // Dictionary previous = new Dictionary(); // if (entity.OriginalValues != null) // { // foreach (var key in entity.OriginalValues.Keys) // previous[key] = entity.OriginalValues.ToString(); // } // base.EditorValueChanged(item, name, value, changes); // if (entity.OriginalValues != null) // { // foreach (var key in entity.OriginalValues.Keys) // { // if (key != name) // { // String oldval = entity.OriginalValues[key] != null ? entity.OriginalValues[key].ToString() : ""; // if ((!previous.ContainsKey(key)) || (!previous[key].Equals(oldval))) // { // if (!changes.Contains(key)) // changes.Add(key); // } // } // } // } //} /*private BitmapImage QAPrintImage(CoreRow arg) { return Wpf.Resources.print.AsBitmapImage(); } private bool QAPrintClick(CoreRow arg) { var formid = arg.Get(x => (x as IDigitalFormInstance).Form.ID); var model = new DigitalFormReportDataModel(new Filter("Parent.ID").IsEqualTo(Item.ID), formid); var section = formid.ToString(); // TODO: This is a hack DynamicGridUtils.PrintMenu?.Invoke(null, section, model, true); return false; }*/ /*private BitmapImage QAEditImage(CoreRow arg) { if (arg == null) return Wpf.Resources.pencil.AsBitmapImage(); var completed = arg.Get(x => (x as IBaseDigitalFormInstance).FormCompleted); return completed.IsEmpty() ? Wpf.Resources.pencil.AsBitmapImage() : Wpf.Resources.view.AsBitmapImage(); } private bool QAEditClick(CoreRow arg) { var item = LoadItem(arg); var result = DynamicFormEditWindow.EditDigitalForm(item as IDigitalFormInstance); if (result) SaveItem(item); return result; }*/ public override DynamicEditorPages LoadEditorPages(TMany item) { return item.ID != Guid.Empty ? base.LoadEditorPages(item) : new DynamicEditorPages(); } protected override bool BeforePaste(IEnumerable items, ClipAction action) { if(action == ClipAction.Copy) { foreach(var item in items) { item.ID = Guid.Empty; } } return base.BeforePaste(items, action); } } }