ListModel.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using InABox.Core;
  8. using System.Diagnostics.CodeAnalysis;
  9. namespace InABox.Mobile
  10. {
  11. public abstract class ListModel<TParent, TItem, TEntity> : Model<TParent,TItem,TEntity>, IListModel<TParent, TItem, TEntity>, IEnumerable<TItem>
  12. where TParent : ListModel<TParent, TItem, TEntity>
  13. where TEntity : Entity, IRemotable, IPersistent, new()
  14. where TItem : Shell<TParent,TEntity>, new()
  15. {
  16. protected ListModel(IModelHost host, Func<Filter<TEntity>> filter, bool transient = false) : base(host, filter, transient)
  17. {
  18. Reset();
  19. }
  20. protected ListModel(IModelHost host, Func<Filter<TEntity>> filter, [NotNull] String filename) : base(host, filter, filename)
  21. {
  22. Reset();
  23. }
  24. protected override void Initialize()
  25. {
  26. _allitems = null;
  27. _items.Clear();
  28. }
  29. public virtual SortOrder<TEntity> Sort => LookupFactory.DefineSort<TEntity>();
  30. private IList<TItem> _allitems;
  31. private CoreTable _table = new CoreTable();
  32. private readonly CoreObservableCollection<TItem> _items = new CoreObservableCollection<TItem>();
  33. public IList<TItem> Items => _items;
  34. IEnumerable IListModel.Items => this.Items;
  35. public Func<TItem, bool> SearchPredicate { get; set; }
  36. public void Search(Func<TItem, bool> predicate)
  37. {
  38. SearchPredicate = predicate;
  39. Search();
  40. }
  41. public void Search()
  42. {
  43. _items.ReplaceRange(
  44. SearchPredicate != null
  45. ? new List<TItem>(_allitems.Where(SearchPredicate))
  46. : new List<TItem>(_allitems)
  47. );
  48. }
  49. protected virtual Expression<Func<TEntity, object>> ImageColumn => null;
  50. public override void BeforeLoad(MultiQuery query)
  51. {
  52. }
  53. public override void AfterLoad(MultiQuery query)
  54. {
  55. }
  56. public override IModel Refresh(bool force)
  57. {
  58. if (!Loaded || force)
  59. Load();
  60. return this;
  61. }
  62. public override void Refresh(bool force, Action loaded)
  63. {
  64. if (!Loaded || force)
  65. Load(loaded);
  66. else
  67. loaded?.Invoke();
  68. }
  69. public override void Load(Action loaded = null)
  70. {
  71. MultiQuery query = new MultiQuery();
  72. query.Add(
  73. Filter(),
  74. GetColumns<TItem,TEntity>(),
  75. Sort
  76. );
  77. if (ImageColumn != null)
  78. {
  79. query.Add<Document>(
  80. new Filter<Document>(x => x.ID).InQuery(Filter(), ImageColumn),
  81. new Columns<Document>(x => x.ID)
  82. .Add(x => x.Data)
  83. );
  84. }
  85. BeforeLoad(query);
  86. // If we have a valid transport, always try and get new data from the server
  87. if (Host.IsConnected())
  88. {
  89. if (loaded != null)
  90. query.Query((q) =>
  91. {
  92. if (Type == ModelType.Persistent)
  93. SaveToStorage(q);
  94. DoAfterLoad(q, loaded);
  95. });
  96. else
  97. {
  98. query.Query();
  99. if (Type == ModelType.Persistent)
  100. SaveToStorage(query);
  101. DoAfterLoad(query);
  102. }
  103. }
  104. else
  105. {
  106. if (Type == ModelType.Transient)
  107. {
  108. InitializeTables(query);
  109. }
  110. else if (Type == ModelType.Normal)
  111. {
  112. // Only load
  113. if (_allitems == null)
  114. InitializeTables(query);
  115. }
  116. else if (Type == ModelType.Persistent)
  117. {
  118. // Treat it as normal, unless its the first time through
  119. // in which case try to load it from storage, if the
  120. // data has been previously cached
  121. if (_allitems == null)
  122. LoadFromStorage(query);
  123. }
  124. DoAfterLoad(query, loaded);
  125. }
  126. }
  127. private void DoAfterLoad(MultiQuery query, Action loaded = null)
  128. {
  129. _table = query.Get<TEntity>();
  130. _allitems = new List<TItem>(query.Get<TEntity>().Rows.Select(row => CreateItem<TItem>(row)));
  131. if (ImageColumn != null)
  132. {
  133. Images.Clear();
  134. query.Get<Document>().IntoDictionary<Document, Guid, byte[]>(Images, x => x.ID,
  135. r => r.Get<Document, byte[]>(x => x.Data));
  136. }
  137. Search(null);
  138. AfterLoad(query);
  139. Loaded = true;
  140. loaded?.Invoke();
  141. NotifyChanged();
  142. }
  143. protected T CreateItem<T>(CoreRow row)
  144. where T : Shell<TParent,TEntity>, new()
  145. {
  146. var result = new T() { Row = row, Parent = (TParent)this };
  147. result.PropertyChanged += (sender, args) => DoPropertyChanged(result, args);
  148. return result;
  149. }
  150. public TItem CreateItem()
  151. {
  152. CoreRow row = _table.NewRow();
  153. var result = CreateItem<TItem>(row);
  154. return result;
  155. }
  156. public void CommitItem(TItem item)
  157. {
  158. _table.Rows.Add(item.Row);
  159. _allitems.Add(item);
  160. NotifyChanged();
  161. }
  162. public TItem AddItem()
  163. {
  164. var result = CreateItem();
  165. CommitItem(result);
  166. return result;
  167. }
  168. public void DeleteItem(TItem item)
  169. {
  170. _table.Rows.Remove(item.Row);
  171. _allitems.Remove(item);
  172. NotifyChanged();
  173. }
  174. object IListModel.CreateItem() => this.CreateItem();
  175. void IListModel.CommitItem(object item)
  176. {
  177. if (item is TItem titem)
  178. CommitItem(titem);
  179. }
  180. object IListModel.AddItem() => this.AddItem();
  181. void IListModel.DeleteItem(object item)
  182. {
  183. if (item is TItem titem)
  184. DeleteItem(titem);
  185. }
  186. IEnumerator<TItem> IEnumerable<TItem>.GetEnumerator()
  187. {
  188. return Items.GetEnumerator();
  189. }
  190. public IEnumerator GetEnumerator()
  191. {
  192. return Items.GetEnumerator();
  193. }
  194. }
  195. }