PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/ObjectListView/Filtering/Filters.cs

https://bitbucket.org/BlueRaja/starbank
C# | 394 lines | 147 code | 42 blank | 205 comment | 17 complexity | 47eca0ad3e6ba0d62cdc91a0c9e08771 MD5 | raw file
  1. /*
  2. * Filters - Filtering on ObjectListViews
  3. *
  4. * Author: Phillip Piper
  5. * Date: 03/03/2010 17:00
  6. *
  7. * Change log:
  8. * 2011-03-01 JPP Added CompositeAllFilter, CompositeAnyFilter and OneOfFilter
  9. * v2.4.1
  10. * 2010-06-23 JPP Extended TextMatchFilter to handle regular expressions and string prefix matching.
  11. * v2.4
  12. * 2010-03-03 JPP Initial version
  13. *
  14. * TO DO:
  15. *
  16. * Copyright (C) 2010 Phillip Piper
  17. *
  18. * This program is free software: you can redistribute it and/or modify
  19. * it under the terms of the GNU General Public License as published by
  20. * the Free Software Foundation, either version 3 of the License, or
  21. * (at your option) any later version.
  22. *
  23. * This program is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. * GNU General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU General Public License
  29. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  30. *
  31. * If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
  32. */
  33. using System;
  34. using System.Collections;
  35. using System.Collections.Generic;
  36. using System.Data;
  37. using System.Reflection;
  38. using System.Drawing;
  39. namespace BrightIdeasSoftware
  40. {
  41. /// <summary>
  42. /// Interface for model-by-model filtering
  43. /// </summary>
  44. public interface IModelFilter
  45. {
  46. /// <summary>
  47. /// Should the given model be included when this filter is installed
  48. /// </summary>
  49. /// <param name="modelObject">The model object to consider</param>
  50. /// <returns>Returns true if the model will be included by the filter</returns>
  51. bool Filter(object modelObject);
  52. }
  53. /// <summary>
  54. /// Interface for whole list filtering
  55. /// </summary>
  56. public interface IListFilter
  57. {
  58. /// <summary>
  59. /// Return a subset of the given list of model objects as the new
  60. /// contents of the ObjectListView
  61. /// </summary>
  62. /// <param name="modelObjects">The collection of model objects that the list will possibly display</param>
  63. /// <returns>The filtered collection that holds the model objects that will be displayed.</returns>
  64. IEnumerable Filter(IEnumerable modelObjects);
  65. }
  66. /// <summary>
  67. /// Base class for model-by-model filters
  68. /// </summary>
  69. public class AbstractModelFilter : IModelFilter
  70. {
  71. /// <summary>
  72. /// Should the given model be included when this filter is installed
  73. /// </summary>
  74. /// <param name="modelObject">The model object to consider</param>
  75. /// <returns>Returns true if the model will be included by the filter</returns>
  76. virtual public bool Filter(object modelObject) {
  77. return true;
  78. }
  79. }
  80. /// <summary>
  81. /// This filter calls a given Predicate to decide if a model object should be included
  82. /// </summary>
  83. public class ModelFilter : IModelFilter
  84. {
  85. /// <summary>
  86. /// Create a filter based on the given predicate
  87. /// </summary>
  88. /// <param name="predicate">The function that will filter objects</param>
  89. public ModelFilter(Predicate<object> predicate) {
  90. this.Predicate = predicate;
  91. }
  92. /// <summary>
  93. /// Gets or sets the predicate used to filter model objects
  94. /// </summary>
  95. protected Predicate<object> Predicate {
  96. get { return predicate; }
  97. set { predicate = value; }
  98. }
  99. private Predicate<object> predicate;
  100. /// <summary>
  101. /// Should the given model object be included?
  102. /// </summary>
  103. /// <param name="modelObject"></param>
  104. /// <returns></returns>
  105. virtual public bool Filter(object modelObject) {
  106. return this.Predicate == null ? true : this.Predicate(modelObject);
  107. }
  108. }
  109. /// <summary>
  110. /// A CompositeFilter joins several other filters together.
  111. /// If there are no filters, all model objects are included
  112. /// </summary>
  113. abstract public class CompositeFilter : IModelFilter {
  114. /// <summary>
  115. /// Create an empty filter
  116. /// </summary>
  117. public CompositeFilter() {
  118. }
  119. /// <summary>
  120. /// Create a composite filter from the given list of filters
  121. /// </summary>
  122. /// <param name="filters">A list of filters</param>
  123. public CompositeFilter(IList<IModelFilter> filters) {
  124. Filters = filters;
  125. }
  126. /// <summary>
  127. /// Gets or sets the filters used by this composite
  128. /// </summary>
  129. public IList<IModelFilter> Filters {
  130. get { return filters; }
  131. set { filters = value; }
  132. }
  133. private IList<IModelFilter> filters = new List<IModelFilter>();
  134. /// <summary>
  135. /// Decide whether or not the given model should be included by the filter
  136. /// </summary>
  137. /// <param name="modelObject"></param>
  138. /// <returns>True if the object is included by the filter</returns>
  139. virtual public bool Filter(object modelObject) {
  140. if (this.Filters == null || this.Filters.Count == 0)
  141. return true;
  142. return this.FilterObject(modelObject);
  143. }
  144. /// <summary>
  145. /// Decide whether or not the given model should be included by the filter
  146. /// </summary>
  147. /// <remarks>Filters is guaranteed to be non-empty when this method is called</remarks>
  148. /// <param name="modelObject">The model object under consideration</param>
  149. /// <returns>True if the object is included by the filter</returns>
  150. abstract public bool FilterObject(object modelObject);
  151. }
  152. /// <summary>
  153. /// A CompositeAllFilter joins several other filters together.
  154. /// A model object must satisfy all filters to be included.
  155. /// If there are no filters, all model objects are included
  156. /// </summary>
  157. public class CompositeAllFilter : CompositeFilter {
  158. /// <summary>
  159. /// Create a filter
  160. /// </summary>
  161. /// <param name="filters"></param>
  162. public CompositeAllFilter(List<IModelFilter> filters)
  163. : base(filters) {
  164. }
  165. /// <summary>
  166. /// Decide whether or not the given model should be included by the filter
  167. /// </summary>
  168. /// <remarks>Filters is guaranteed to be non-empty when this method is called</remarks>
  169. /// <param name="modelObject">The model object under consideration</param>
  170. /// <returns>True if the object is included by the filter</returns>
  171. override public bool FilterObject(object modelObject) {
  172. foreach (IModelFilter filter in this.Filters)
  173. if (!filter.Filter(modelObject))
  174. return false;
  175. return true;
  176. }
  177. }
  178. /// <summary>
  179. /// A CompositeAllFilter joins several other filters together.
  180. /// A model object must only satisfy one of the filters to be included.
  181. /// If there are no filters, all model objects are included
  182. /// </summary>
  183. public class CompositeAnyFilter : CompositeFilter {
  184. /// <summary>
  185. /// Create a filter from the given filters
  186. /// </summary>
  187. /// <param name="filters"></param>
  188. public CompositeAnyFilter(List<IModelFilter> filters)
  189. : base(filters) {
  190. }
  191. /// <summary>
  192. /// Decide whether or not the given model should be included by the filter
  193. /// </summary>
  194. /// <remarks>Filters is guaranteed to be non-empty when this method is called</remarks>
  195. /// <param name="modelObject">The model object under consideration</param>
  196. /// <returns>True if the object is included by the filter</returns>
  197. override public bool FilterObject(object modelObject) {
  198. foreach (IModelFilter filter in this.Filters)
  199. if (filter.Filter(modelObject))
  200. return true;
  201. return false;
  202. }
  203. }
  204. /// <summary>
  205. /// Instances of this class extract a value from the model object
  206. /// and compare that value to a list of fixed values. The model
  207. /// object is included if the extracted value is in the list
  208. /// </summary>
  209. /// <remarks>If there is no delegate installed or there are
  210. /// no values to match, no model objects will be matched</remarks>
  211. public class OneOfFilter : IModelFilter {
  212. /// <summary>
  213. /// Create a filter that will use the given delegate to extract values
  214. /// </summary>
  215. /// <param name="valueGetter"></param>
  216. public OneOfFilter(AspectGetterDelegate valueGetter) :
  217. this(valueGetter, new ArrayList()) {
  218. }
  219. /// <summary>
  220. /// Create a filter that will extract values using the given delegate
  221. /// and compare them to the values in the given list.
  222. /// </summary>
  223. /// <param name="valueGetter"></param>
  224. /// <param name="possibleValues"></param>
  225. public OneOfFilter(AspectGetterDelegate valueGetter, ICollection possibleValues) {
  226. this.ValueGetter = valueGetter;
  227. this.PossibleValues = new ArrayList(possibleValues);
  228. }
  229. /// <summary>
  230. /// Gets or sets the delegate that will be used to extract values
  231. /// from model objects
  232. /// </summary>
  233. public AspectGetterDelegate ValueGetter {
  234. get { return valueGetter; }
  235. set { valueGetter = value; }
  236. }
  237. private AspectGetterDelegate valueGetter;
  238. /// <summary>
  239. /// Gets or sets the list of values that the value extracted from
  240. /// the model object must match in order to be included.
  241. /// </summary>
  242. public IList PossibleValues {
  243. get { return possibleValues; }
  244. set { possibleValues = value; }
  245. }
  246. private IList possibleValues;
  247. /// <summary>
  248. /// Should the given model object be included?
  249. /// </summary>
  250. /// <param name="modelObject"></param>
  251. /// <returns></returns>
  252. public virtual bool Filter(object modelObject) {
  253. if (this.ValueGetter == null || this.PossibleValues == null || this.PossibleValues.Count == 0)
  254. return false;
  255. return this.PossibleValues.Contains(this.ValueGetter(modelObject));
  256. }
  257. }
  258. /// <summary>
  259. /// Base class for whole list filters
  260. /// </summary>
  261. public class AbstractListFilter : IListFilter
  262. {
  263. /// <summary>
  264. /// Return a subset of the given list of model objects as the new
  265. /// contents of the ObjectListView
  266. /// </summary>
  267. /// <param name="modelObjects">The collection of model objects that the list will possibly display</param>
  268. /// <returns>The filtered collection that holds the model objects that will be displayed.</returns>
  269. virtual public IEnumerable Filter(IEnumerable modelObjects) {
  270. return modelObjects;
  271. }
  272. }
  273. /// <summary>
  274. /// Instance of this class implement delegate based whole list filtering
  275. /// </summary>
  276. public class ListFilter : AbstractListFilter
  277. {
  278. /// <summary>
  279. /// A delegate that filters on a whole list
  280. /// </summary>
  281. /// <param name="rowObjects"></param>
  282. /// <returns></returns>
  283. public delegate IEnumerable ListFilterDelegate(IEnumerable rowObjects);
  284. /// <summary>
  285. /// Create a ListFilter
  286. /// </summary>
  287. /// <param name="function"></param>
  288. public ListFilter(ListFilterDelegate function) {
  289. this.Function = function;
  290. }
  291. /// <summary>
  292. /// Gets or sets the delegate that will filter the list
  293. /// </summary>
  294. public ListFilterDelegate Function {
  295. get { return function; }
  296. set { function = value; }
  297. }
  298. private ListFilterDelegate function;
  299. /// <summary>
  300. /// Do the actual work of filtering
  301. /// </summary>
  302. /// <param name="modelObjects"></param>
  303. /// <returns></returns>
  304. public override IEnumerable Filter(IEnumerable modelObjects) {
  305. if (this.Function == null)
  306. return modelObjects;
  307. return this.Function(modelObjects);
  308. }
  309. }
  310. /// <summary>
  311. /// Filter the list so only the last N entries are displayed
  312. /// </summary>
  313. public class TailFilter : AbstractListFilter
  314. {
  315. /// <summary>
  316. /// Create a no-op tail filter
  317. /// </summary>
  318. public TailFilter() {
  319. }
  320. /// <summary>
  321. /// Create a filter that includes on the last N model objects
  322. /// </summary>
  323. /// <param name="numberOfObjects"></param>
  324. public TailFilter(int numberOfObjects) {
  325. this.Count = numberOfObjects;
  326. }
  327. /// <summary>
  328. /// Gets or sets the number of model objects that will be
  329. /// returned from the tail of the list
  330. /// </summary>
  331. public int Count {
  332. get { return count; }
  333. set { count = value; }
  334. }
  335. private int count;
  336. /// <summary>
  337. /// Return the last N subset of the model objects
  338. /// </summary>
  339. /// <param name="modelObjects"></param>
  340. /// <returns></returns>
  341. public override IEnumerable Filter(IEnumerable modelObjects) {
  342. if (this.Count <= 0)
  343. return modelObjects;
  344. ArrayList list = ObjectListView.EnumerableToArray(modelObjects, false);
  345. if (this.Count > list.Count)
  346. return list;
  347. object[] tail = new object[this.Count];
  348. list.CopyTo(list.Count - this.Count, tail, 0, this.Count);
  349. return new ArrayList(tail);
  350. }
  351. }
  352. }