PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/Interlace/Collections/SortedAdapterCollection.cs

https://bitbucket.org/VahidN/interlace
C# | 500 lines | 351 code | 120 blank | 29 comment | 45 complexity | 0038edd60d9230217be03440081635ed MD5 | raw file
  1. #region Using Directives and Copyright Notice
  2. // Copyright (c) 2010, Bit Plantation
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of the Bit Plantation nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. // ARE DISCLAIMED. IN NO EVENT SHALL COMPUTER CONSULTANCY PTY LTD BE LIABLE
  20. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  26. // DAMAGE.
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Text;
  30. using System.ComponentModel;
  31. using System.Collections;
  32. #endregion
  33. namespace Interlace.Collections
  34. {
  35. public abstract class SortedAdapterCollection<TAdapter, TValue, TKey> : IBindingList, IList<TAdapter> where TAdapter : class
  36. {
  37. SortedList<TKey, TAdapter> _list = new SortedList<TKey, TAdapter>();
  38. protected abstract TKey GetKeyFromValue(TValue value);
  39. protected abstract TKey GetKeyFromAdapter(TAdapter adapter);
  40. protected abstract TAdapter CreateAdapter(TValue value);
  41. protected abstract void UpdateAdapter(TValue value, TAdapter adapter);
  42. public void Merge(IList<TValue> source)
  43. {
  44. // Build a dictionary of existing items (that we later mutate in a gross way):
  45. Dictionary<TKey, int> existingIndicies = new Dictionary<TKey, int>();
  46. int i = 0;
  47. foreach (TAdapter item in this)
  48. {
  49. existingIndicies[GetKeyFromAdapter(item)] = i;
  50. i++;
  51. }
  52. // Add new entities, and update existing entities:
  53. foreach (TValue sourceItem in source)
  54. {
  55. int foundIndex;
  56. TKey sourceKey = GetKeyFromValue(sourceItem);
  57. bool found = existingIndicies.TryGetValue(sourceKey, out foundIndex);
  58. if (found)
  59. {
  60. UpdateAdapter(sourceItem, _list.Values[foundIndex]);
  61. existingIndicies.Remove(sourceKey);
  62. }
  63. else
  64. {
  65. Add(sourceKey, CreateAdapter(sourceItem));
  66. }
  67. }
  68. // Remove missing entities:
  69. List<int> indiciesToRemove = new List<int>(existingIndicies.Values);
  70. indiciesToRemove.Sort();
  71. int indiciesRemoved = 0;
  72. foreach (int index in indiciesToRemove)
  73. {
  74. RemoveAt(index - indiciesRemoved);
  75. indiciesRemoved++;
  76. }
  77. }
  78. public void Update(IList<TValue> partialSource)
  79. {
  80. // Add new entities, and update existing entities:
  81. foreach (TValue sourceItem in partialSource)
  82. {
  83. TKey sourceKey = GetKeyFromValue(sourceItem);
  84. int foundIndex = _list.IndexOfKey(sourceKey);
  85. if (foundIndex != -1)
  86. {
  87. UpdateAdapter(sourceItem, _list.Values[foundIndex]);
  88. }
  89. else
  90. {
  91. Add(sourceKey, CreateAdapter(sourceItem));
  92. }
  93. }
  94. }
  95. public TAdapter FindByKey(TKey key)
  96. {
  97. int index = _list.IndexOfKey(key);
  98. if (index != -1)
  99. {
  100. return _list.Values[index];
  101. }
  102. else
  103. {
  104. return null;
  105. }
  106. }
  107. public event EventHandler<AdapterCollectionItemEventArgs<TAdapter>> ItemAdding;
  108. public event EventHandler<AdapterCollectionItemEventArgs<TAdapter>> ItemRemoving;
  109. void HandleItemAdding(TKey key, TAdapter adapter)
  110. {
  111. if (adapter is INotifyPropertyChanged)
  112. {
  113. INotifyPropertyChanged implementation = adapter as INotifyPropertyChanged;
  114. implementation.PropertyChanged += new PropertyChangedEventHandler(implementation_PropertyChanged);
  115. }
  116. if (ItemAdding != null) ItemAdding(this, new AdapterCollectionItemEventArgs<TAdapter>(adapter));
  117. }
  118. void HandleItemRemoving(TKey key, TAdapter adapter)
  119. {
  120. if (adapter is INotifyPropertyChanged)
  121. {
  122. INotifyPropertyChanged implementation = adapter as INotifyPropertyChanged;
  123. implementation.PropertyChanged -= new PropertyChangedEventHandler(implementation_PropertyChanged);
  124. }
  125. if (ItemAdding != null) ItemRemoving(this, new AdapterCollectionItemEventArgs<TAdapter>(adapter));
  126. }
  127. void implementation_PropertyChanged(object sender, PropertyChangedEventArgs e)
  128. {
  129. if (ListChanged == null) return;
  130. TAdapter adapter = sender as TAdapter;
  131. if (adapter == null) return;
  132. TKey key = GetKeyFromAdapter(adapter);
  133. int index = _list.IndexOfKey(key);
  134. if (index == -1) return;
  135. ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, index));
  136. }
  137. #region IBindingList Members
  138. public void AddIndex(PropertyDescriptor property)
  139. {
  140. }
  141. public object AddNew()
  142. {
  143. throw new InvalidOperationException();
  144. }
  145. public bool AllowEdit
  146. {
  147. get { return true; }
  148. }
  149. public bool AllowNew
  150. {
  151. get { return false; }
  152. }
  153. public bool AllowRemove
  154. {
  155. get { return true; }
  156. }
  157. public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
  158. {
  159. throw new NotSupportedException();
  160. }
  161. public int Find(PropertyDescriptor property, object key)
  162. {
  163. throw new NotSupportedException();
  164. }
  165. public bool IsSorted
  166. {
  167. get { throw new NotSupportedException(); }
  168. }
  169. public void RemoveIndex(PropertyDescriptor property)
  170. {
  171. }
  172. public void RemoveSort()
  173. {
  174. throw new NotSupportedException();
  175. }
  176. public ListSortDirection SortDirection
  177. {
  178. get { throw new NotSupportedException(); }
  179. }
  180. public PropertyDescriptor SortProperty
  181. {
  182. get { throw new NotSupportedException(); }
  183. }
  184. public bool SupportsChangeNotification
  185. {
  186. get { return true; }
  187. }
  188. public bool SupportsSearching
  189. {
  190. get { return false; }
  191. }
  192. public bool SupportsSorting
  193. {
  194. get { return false; }
  195. }
  196. public event ListChangedEventHandler ListChanged;
  197. #endregion
  198. public void Add(TKey key, TAdapter adapter)
  199. {
  200. if (_list.ContainsKey(key))
  201. {
  202. throw new ArgumentException("An element with the same key already exists.", "value");
  203. }
  204. HandleItemAdding(key, adapter);
  205. _list.Add(key, adapter);
  206. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
  207. }
  208. #region IList Members
  209. public int Add(object value)
  210. {
  211. TAdapter adapter = value as TAdapter;
  212. TKey key = GetKeyFromAdapter(adapter);
  213. Add(key, adapter);
  214. return _list.IndexOfKey(key);
  215. }
  216. public void Clear()
  217. {
  218. foreach (KeyValuePair<TKey, TAdapter> pair in _list)
  219. {
  220. HandleItemRemoving(pair.Key, pair.Value);
  221. }
  222. _list.Clear();
  223. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
  224. }
  225. public bool Contains(object value)
  226. {
  227. return _list.ContainsValue(value as TAdapter);
  228. }
  229. public int IndexOf(object value)
  230. {
  231. return _list.IndexOfValue(value as TAdapter);
  232. }
  233. public void Insert(int index, object value)
  234. {
  235. Add(value);
  236. }
  237. public bool IsFixedSize
  238. {
  239. get { return false; }
  240. }
  241. public bool IsReadOnly
  242. {
  243. get { return false; }
  244. }
  245. public void Remove(object value)
  246. {
  247. TAdapter adapter = value as TAdapter;
  248. if (adapter == null)
  249. {
  250. throw new ArgumentException("An object of the adapter type was expected.", "value");
  251. }
  252. TKey key = GetKeyFromAdapter(adapter);
  253. if (!_list.ContainsKey(key)) return;
  254. HandleItemRemoving(key, adapter);
  255. _list.Remove(key);
  256. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
  257. }
  258. public void RemoveAt(int index)
  259. {
  260. if (0 <= index && index < _list.Count)
  261. {
  262. HandleItemRemoving(_list.Keys[index], _list.Values[index]);
  263. }
  264. _list.RemoveAt(index);
  265. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
  266. }
  267. public object this[int index]
  268. {
  269. get
  270. {
  271. return _list.Values[index];
  272. }
  273. set
  274. {
  275. TAdapter oldAdapter = _list.Values[index];
  276. TAdapter newAdapter = value as TAdapter;
  277. if (object.ReferenceEquals(oldAdapter, newAdapter)) return;
  278. if (newAdapter == null)
  279. {
  280. throw new ArgumentException("An object of the adapter type was expected.");
  281. }
  282. HandleItemRemoving(_list.Keys[index], oldAdapter);
  283. HandleItemAdding(_list.Keys[index], newAdapter);
  284. _list.Values[index] = newAdapter;
  285. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, index));
  286. }
  287. }
  288. #endregion
  289. #region ICollection Members
  290. public void CopyTo(Array array, int index)
  291. {
  292. for (int i = 0; i < _list.Count; i++)
  293. {
  294. array.SetValue(_list.Values[i], index + i);
  295. }
  296. }
  297. public int Count
  298. {
  299. get { return _list.Count; }
  300. }
  301. public bool IsSynchronized
  302. {
  303. get { return false; }
  304. }
  305. public object SyncRoot
  306. {
  307. get { throw new NotSupportedException(); }
  308. }
  309. #endregion
  310. #region IEnumerable Members
  311. public IEnumerator GetEnumerator()
  312. {
  313. return _list.Values.GetEnumerator();
  314. }
  315. #endregion
  316. #region IList<TAdapter> Members
  317. public int IndexOf(TAdapter item)
  318. {
  319. return _list.IndexOfValue(item);
  320. }
  321. public void Insert(int index, TAdapter item)
  322. {
  323. Add(item);
  324. }
  325. TAdapter IList<TAdapter>.this[int index]
  326. {
  327. get
  328. {
  329. return _list.Values[index];
  330. }
  331. set
  332. {
  333. TAdapter oldAdapter = _list.Values[index];
  334. TAdapter newAdapter = value;
  335. if (object.ReferenceEquals(oldAdapter, newAdapter)) return;
  336. if (newAdapter == null)
  337. {
  338. throw new ArgumentException("An object of the adapter type was expected.");
  339. }
  340. HandleItemRemoving(_list.Keys[index], oldAdapter);
  341. HandleItemAdding(_list.Keys[index], newAdapter);
  342. _list.Values[index] = newAdapter;
  343. if (ListChanged != null) ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemChanged, index));
  344. }
  345. }
  346. #endregion
  347. #region ICollection<TAdapter> Members
  348. public void Add(TAdapter item)
  349. {
  350. if (item == null)
  351. {
  352. throw new ArgumentException("An object of the adapter type was expected.", "value");
  353. }
  354. TKey key = GetKeyFromAdapter(item);
  355. Add(key, item);
  356. }
  357. public bool Contains(TAdapter item)
  358. {
  359. return _list.ContainsValue(item);
  360. }
  361. public void CopyTo(TAdapter[] array, int arrayIndex)
  362. {
  363. for (int i = 0; i < _list.Count; i++)
  364. {
  365. array[arrayIndex + i] = _list.Values[i];
  366. }
  367. }
  368. public bool Remove(TAdapter item)
  369. {
  370. throw new Exception("The method or operation is not implemented.");
  371. }
  372. #endregion
  373. #region IEnumerable<TAdapter> Members
  374. IEnumerator<TAdapter> IEnumerable<TAdapter>.GetEnumerator()
  375. {
  376. return _list.Values.GetEnumerator();
  377. }
  378. #endregion
  379. }
  380. }