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

/EventScavenger/Version4/BinaryComponents.SuperList/ItemList/BufferedItemList.cs

#
C# | 463 lines | 396 code | 42 blank | 25 comment | 59 complexity | 6fa142e167a96e39e9e74c20c74c719f MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (c) 2007 BinaryComponents Ltd. All Rights Reserved.
  4. //
  5. // http://www.binarycomponents.com/
  6. //
  7. /////////////////////////////////////////////////////////////////////////////
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.Text;
  12. using BinaryComponents.Utility.Collections;
  13. using System.Threading;
  14. namespace BinaryComponents.SuperList.ItemLists
  15. {
  16. public class BufferedList : ItemList
  17. {
  18. public override int Count
  19. {
  20. get
  21. {
  22. lock( _lockObject )
  23. {
  24. return _sortedListItems.Length;// +_deferredAdditions.Count;// 0; // _deferredAdditions.Count;
  25. }
  26. }
  27. }
  28. public override void Clear()
  29. {
  30. lock( _lockObject )
  31. {
  32. _sortedListItems = new object[0];
  33. this.ListUpdated( false );
  34. _deferredAdditions.Clear();
  35. _deferredDeletions.Clear();
  36. }
  37. }
  38. public override void Add( object item )
  39. {
  40. lock( _lockObject )
  41. {
  42. if( !_deferredAdditions.Contains( item ) )
  43. {
  44. _deferredAdditions.Add( item );
  45. }
  46. }
  47. }
  48. public override void AddRange( IEnumerable items )
  49. {
  50. foreach( object item in items )
  51. {
  52. this.Add( item );
  53. }
  54. }
  55. public override int IndexOf( object o )
  56. {
  57. Dictionary<object, int> mapItems = null;
  58. lock( _lockObject )
  59. {
  60. if( _mapItems != null )
  61. {
  62. mapItems = (Dictionary<object, int>)_mapItems.Target;
  63. }
  64. if( mapItems == null )
  65. {
  66. mapItems = new Dictionary<object, int>();
  67. if( _sortedListItems != null )
  68. {
  69. for( int i = 0; i < _sortedListItems.Length; i++ )
  70. {
  71. mapItems[_sortedListItems[i]] = i;
  72. }
  73. }
  74. _mapItems = new WeakReference( mapItems );
  75. }
  76. }
  77. int result;
  78. if( !mapItems.TryGetValue( o, out result ) )
  79. {
  80. result = -1;
  81. }
  82. return result;
  83. }
  84. WeakReference _mapItems = null;
  85. public override void Remove( object item )
  86. {
  87. lock( _lockObject )
  88. {
  89. _deferredAdditions.Remove( item );
  90. if( !_deferredDeletions.Contains( item ) )
  91. {
  92. _deferredDeletions.Add( item );
  93. }
  94. }
  95. }
  96. public override void ItemsChanged( params object[] items )
  97. {
  98. bool reLayout = false;
  99. //
  100. // only need to be concerned if the sort order changes
  101. if( ( _jobGroupColumns != null && _jobGroupColumns.Length > 0 ) || (_jobSortColumns != null && _jobSortColumns.Length > 0) )
  102. {
  103. lock( _lockObject )
  104. {
  105. ColumnComparer comparer = new ColumnComparer( _jobGroupColumns, _jobSortColumns, this );
  106. //
  107. // Check to see if changes have an effect of the sort order.
  108. // if they do then we add them to the deletes and adds.
  109. // Otherwise we don't need to do anything.
  110. foreach( object o in items )
  111. {
  112. int searchResult = Array.BinarySearch( _sortedListItems, o, comparer );
  113. if( searchResult < 0 )
  114. {
  115. searchResult = ~searchResult;
  116. }
  117. if( searchResult < _sortedListItems.Length )
  118. {
  119. if( _sortedListItems[searchResult] == o )
  120. {
  121. reLayout = true; // visually may have changed so we layout
  122. }
  123. else
  124. {
  125. _deferredDeletions.Add( o );
  126. _deferredAdditions.Add( o );
  127. }
  128. }
  129. }
  130. }
  131. }
  132. if( reLayout )
  133. {
  134. this.ListControl.UpdateListSection( true );
  135. }
  136. }
  137. public override void RemoveRange( IEnumerable items )
  138. {
  139. foreach( object item in items )
  140. {
  141. this.Remove( item );
  142. }
  143. }
  144. public override object[] ToArray()
  145. {
  146. return _sortedListItems;
  147. }
  148. public override void SynchroniseWithUINow()
  149. {
  150. DoHouseKeeping( false );
  151. }
  152. #region Implementation
  153. #region ListControl communication methods
  154. //protected internal override object this[int index]
  155. public override object this[int index]
  156. {
  157. get
  158. {
  159. lock( _lockObject )
  160. {
  161. if ((_sortedListItems.Length) > index)
  162. return _sortedListItems[index];
  163. else
  164. return null;
  165. }
  166. }
  167. }
  168. public override void Sort()
  169. {
  170. _sortNeeded = true;
  171. }
  172. protected internal override void DoHouseKeeping()
  173. {
  174. DoHouseKeeping( this.ProcessingStyle == ProcessingStyle.Thread );
  175. }
  176. #endregion
  177. private void DoHouseKeeping( bool runInBackground )
  178. {
  179. if( runInBackground )
  180. {
  181. CheckForJobCompletionResults();
  182. CheckForSortJob( runInBackground );
  183. }
  184. else
  185. {
  186. //
  187. // Spin wait if we have a queued job
  188. while( true )
  189. {
  190. lock( _lockObject )
  191. {
  192. if( !_jobQueued )
  193. {
  194. break;
  195. }
  196. }
  197. Thread.Sleep( 50 );
  198. }
  199. CheckForSortJob( false );
  200. CheckForJobCompletionResults();
  201. }
  202. }
  203. private void CheckForJobCompletionResults()
  204. {
  205. lock( _lockObject )
  206. {
  207. if( !_jobQueued )
  208. {
  209. if( _jobSortedList != null )
  210. {
  211. this.GroupColumns = _jobGroupColumns;
  212. _sortedListItems = _jobSortedList.ToArray();
  213. _jobSortedList = null;
  214. _mapItems = null;
  215. this.ListUpdated( false );
  216. }
  217. }
  218. }
  219. }
  220. private void CheckForSortJob( bool runInBackground )
  221. {
  222. lock( _lockObject )
  223. {
  224. if( !_jobQueued )
  225. {
  226. if( _deferredAdditions.Count > 0 || _deferredDeletions.Count > 0 || _sortNeeded )
  227. {
  228. _jobSortNeeded = _sortNeeded;
  229. _sortNeeded = false;
  230. _jobQueued = true;
  231. _jobGroupColumns = this.GetGroupColumnsCopy();
  232. _jobSortColumns = this.GetSortColumnsCopy();
  233. if( runInBackground )
  234. {
  235. ThreadPool.QueueUserWorkItem( new WaitCallback( UpdateJob ) );
  236. }
  237. else
  238. {
  239. UpdateJob( null );
  240. }
  241. }
  242. }
  243. }
  244. }
  245. private void UpdateJob( object state )
  246. {
  247. try
  248. {
  249. object []additions;
  250. object[] oldSortedList;
  251. Set<object> deferredDeletions = new Set<object>();
  252. bool sortNeeded;
  253. lock( _lockObject ) // nip in to the shared areas and take a copy of the data
  254. {
  255. additions = _deferredAdditions.ToArray();
  256. deferredDeletions = new Set<object>( _deferredDeletions );
  257. oldSortedList = (object[])_sortedListItems.Clone();
  258. _deferredAdditions.Clear();
  259. _deferredDeletions.Clear();
  260. sortNeeded = _jobSortNeeded;
  261. _jobSortNeeded = false;
  262. }
  263. List<object> newSortedList = new List<object>( _sortedListItems.Length + additions.Length );
  264. //
  265. // Copy the necessary lists
  266. if( deferredDeletions.Count > 0 )
  267. {
  268. for( int i = 0; i < oldSortedList.Length; i++ )
  269. {
  270. object item = oldSortedList[i];
  271. if( !deferredDeletions.Contains( item ) )
  272. {
  273. newSortedList.Add( item );
  274. }
  275. }
  276. }
  277. else
  278. {
  279. newSortedList = new List<object>( _sortedListItems );
  280. }
  281. ColumnComparer comparer = new ColumnComparer( _jobGroupColumns, _jobSortColumns, this );
  282. //
  283. // Perform sort.
  284. if( !sortNeeded && additions.Length != 0 && newSortedList.Count > additions.Length )
  285. {
  286. //
  287. // We insert the new entries using BinarySearch since the
  288. // default sort for the Clr is QuickSort which works best on
  289. // unsorted lists.
  290. foreach( object item in additions )
  291. {
  292. int searchResult = newSortedList.BinarySearch( item, comparer );
  293. if( searchResult < 0 )
  294. {
  295. searchResult = ~searchResult;
  296. }
  297. newSortedList.Insert( searchResult, item );
  298. }
  299. }
  300. else
  301. {
  302. newSortedList.AddRange( additions );
  303. newSortedList.Sort( comparer );
  304. }
  305. lock( _lockObject )
  306. {
  307. _jobSortedList = newSortedList;
  308. }
  309. }
  310. finally
  311. {
  312. _jobQueued = false;
  313. }
  314. }
  315. #region ColumnComparer
  316. private class ColumnComparer: IComparer<object>
  317. {
  318. public ColumnComparer( Column[] groupByColumns, Column[] sortByColumns, BufferedList list )
  319. {
  320. _list = list;
  321. _groupByColumns = groupByColumns;
  322. _sortByColumns = sortByColumns;
  323. }
  324. public int Compare( object x, object y )
  325. {
  326. if( x == y )
  327. {
  328. return 0;
  329. }
  330. foreach( Column _column in _groupByColumns )
  331. {
  332. int result = _column.GroupedComparitor( x, y );
  333. if( result != 0 )
  334. {
  335. return _column.GroupSortOrder == System.Windows.Forms.SortOrder.Descending ? -result : result;
  336. }
  337. }
  338. if( _sortByColumns.Length == 0 )
  339. {
  340. foreach( Column column in _groupByColumns )
  341. {
  342. int result = column.Comparitor( x, y );
  343. if( result != 0 )
  344. {
  345. return column.GroupSortOrder == System.Windows.Forms.SortOrder.Descending ? -result : result;
  346. }
  347. }
  348. }
  349. else
  350. {
  351. foreach( Column column in _sortByColumns )
  352. {
  353. int result = column.Comparitor( x, y );
  354. if( result != 0 )
  355. {
  356. return column.SortOrder == System.Windows.Forms.SortOrder.Descending ? -result : result;
  357. }
  358. }
  359. }
  360. if( x is IComparable )
  361. {
  362. return ((IComparable)x).CompareTo( y );
  363. }
  364. if (_list.ObjectComparer == null)
  365. {
  366. return 0;
  367. //throw new InvalidOperationException("ItemList.ObjectComparer must be set");
  368. }
  369. else
  370. return _list.ObjectComparer.Compare(x, y);
  371. }
  372. private BufferedList _list;
  373. private Column[] _groupByColumns;
  374. private Column[] _sortByColumns;
  375. }
  376. #endregion
  377. private Column[] GetSortColumnsCopy()
  378. {
  379. List<Column> columns = new List<Column>();
  380. foreach( Column column in this.ListControl.Columns.VisibleItems )
  381. {
  382. if( column.SortOrder != System.Windows.Forms.SortOrder.None )
  383. {
  384. columns.Add( new Column( column ) );
  385. }
  386. }
  387. return columns.ToArray();
  388. }
  389. private Column[] GetGroupColumnsCopy()
  390. {
  391. List<Column> columns = new List<Column>();
  392. foreach( Column column in this.ListControl.Columns.GroupedItems )
  393. {
  394. columns.Add( new Column( column ) );
  395. }
  396. return columns.ToArray();
  397. }
  398. private enum ActionType{ Add, Remove };
  399. private struct Action
  400. {
  401. public Action( ActionType actionType, object item )
  402. {
  403. this.ActionType = actionType;
  404. this.Item = item;
  405. }
  406. public readonly ActionType ActionType;
  407. public readonly object Item;
  408. }
  409. private Set<object> _deferredAdditions = new Set<object>();
  410. private Set<object> _deferredDeletions = new Set<object>();
  411. private bool _sortNeeded = false;
  412. private bool _jobQueued = false; // trigger for job to be run
  413. private bool _jobSortNeeded = false;
  414. private Column[] _jobSortColumns = null;
  415. private Column[] _jobGroupColumns = null;
  416. private List<object> _jobSortedList = null;
  417. private object _lockObject = new object();
  418. private object [] _sortedListItems = new object[0];
  419. #endregion
  420. }
  421. }