/* * Comparers - Various Comparer classes used within ObjectListView * * Author: Phillip Piper * Date: 25/11/2008 17:15 * * Change log: * v2.3 * 2009-08-24 JPP - Added OLVGroupComparer * 2009-06-01 JPP - ModelObjectComparer would crash if secondary sort column was null. * 2008-12-20 JPP - Fixed bug with group comparisons when a group key was null (SF#2445761) * 2008-11-25 JPP Initial version * * TO DO: * * Copyright (C) 2006-2014 Phillip Piper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com. */ using System; using System.Collections; using System.Collections.Generic; using System.Windows.Forms; namespace BrightIdeasSoftware { /// /// ColumnComparer is the workhorse for all comparison between two values of a particular column. /// If the column has a specific comparer, use that to compare the values. Otherwise, do /// a case insensitive string compare of the string representations of the values. /// /// This class inherits from both IComparer and its generic counterpart /// so that it can be used on untyped and typed collections. public class ColumnComparer : IComparer, IComparer { /// /// Create a ColumnComparer that will order the rows in a list view according /// to the values in a given column /// /// The column whose values will be compared /// The ordering for column values public ColumnComparer(OLVColumn col, SortOrder order) { this.column = col; this.sortOrder = order; } /// /// Create a ColumnComparer that will order the rows in a list view according /// to the values in a given column, and by a secondary column if the primary /// column is equal. /// /// The column whose values will be compared /// The ordering for column values /// The column whose values will be compared for secondary sorting /// The ordering for secondary column values public ColumnComparer(OLVColumn col, SortOrder order, OLVColumn col2, SortOrder order2) : this(col, order) { // There is no point in secondary sorting on the same column if (col != col2) this.secondComparer = new ColumnComparer(col2, order2); } /// /// Compare two rows /// /// row1 /// row2 /// An ordering indication: -1, 0, 1 public int Compare(object x, object y) { return this.Compare((OLVListItem)x, (OLVListItem)y); } /// /// Compare two rows /// /// row1 /// row2 /// An ordering indication: -1, 0, 1 public int Compare(OLVListItem x, OLVListItem y) { if (this.sortOrder == SortOrder.None) return 0; int result = 0; object x1 = this.column.GetValue(x.RowObject); object y1 = this.column.GetValue(y.RowObject); // Handle nulls. Null values come last bool xIsNull = (x1 == null || x1 == System.DBNull.Value); bool yIsNull = (y1 == null || y1 == System.DBNull.Value); if (xIsNull || yIsNull) { if (xIsNull && yIsNull) result = 0; else result = (xIsNull ? -1 : 1); } else { result = this.CompareValues(x1, y1); } if (this.sortOrder == SortOrder.Descending) result = 0 - result; // If the result was equality, use the secondary comparer to resolve it if (result == 0 && this.secondComparer != null) result = this.secondComparer.Compare(x, y); return result; } /// /// Compare the actual values to be used for sorting /// /// The aspect extracted from the first row /// The aspect extracted from the second row /// An ordering indication: -1, 0, 1 public int CompareValues(object x, object y) { // Force case insensitive compares on strings String xAsString = x as String; if (xAsString != null) return String.Compare(xAsString, (String)y, StringComparison.CurrentCultureIgnoreCase); else { IComparable comparable = x as IComparable; if (comparable != null) return comparable.CompareTo(y); else return 0; } } private OLVColumn column; private SortOrder sortOrder; private ColumnComparer secondComparer; } /// /// This comparer sort list view groups. OLVGroups have a "SortValue" property, /// which is used if present. Otherwise, the titles of the groups will be compared. /// public class OLVGroupComparer : IComparer { /// /// Create a group comparer /// /// The ordering for column values public OLVGroupComparer(SortOrder order) { this.sortOrder = order; } /// /// Compare the two groups. OLVGroups have a "SortValue" property, /// which is used if present. Otherwise, the titles of the groups will be compared. /// /// group1 /// group2 /// An ordering indication: -1, 0, 1 public int Compare(OLVGroup x, OLVGroup y) { // If we can compare the sort values, do that. // Otherwise do a case insensitive compare on the group header. int result; if (x.SortValue != null && y.SortValue != null) result = x.SortValue.CompareTo(y.SortValue); else result = String.Compare(x.Header, y.Header, StringComparison.CurrentCultureIgnoreCase); if (this.sortOrder == SortOrder.Descending) result = 0 - result; return result; } private SortOrder sortOrder; } /// /// This comparer can be used to sort a collection of model objects by a given column /// public class ModelObjectComparer : IComparer, IComparer { /// /// Create a model object comparer /// /// /// public ModelObjectComparer(OLVColumn col, SortOrder order) { this.column = col; this.sortOrder = order; } /// /// Create a model object comparer with a secondary sorting column /// /// /// /// /// public ModelObjectComparer(OLVColumn col, SortOrder order, OLVColumn col2, SortOrder order2) : this(col, order) { // There is no point in secondary sorting on the same column if (col != col2 && col2 != null && order2 != SortOrder.None) this.secondComparer = new ModelObjectComparer(col2, order2); } /// /// Compare the two model objects /// /// /// /// public int Compare(object x, object y) { int result = 0; object x1 = this.column.GetValue(x); object y1 = this.column.GetValue(y); if (this.sortOrder == SortOrder.None) return 0; // Handle nulls. Null values come last bool xIsNull = (x1 == null || x1 == System.DBNull.Value); bool yIsNull = (y1 == null || y1 == System.DBNull.Value); if (xIsNull || yIsNull) { if (xIsNull && yIsNull) result = 0; else result = (xIsNull ? -1 : 1); } else { result = this.CompareValues(x1, y1); } if (this.sortOrder == SortOrder.Descending) result = 0 - result; // If the result was equality, use the secondary comparer to resolve it if (result == 0 && this.secondComparer != null) result = this.secondComparer.Compare(x, y); return result; } /// /// Compare the actual values /// /// /// /// public int CompareValues(object x, object y) { // Force case insensitive compares on strings String xStr = x as String; if (xStr != null) return String.Compare(xStr, (String)y, StringComparison.CurrentCultureIgnoreCase); else { IComparable comparable = x as IComparable; if (comparable != null) return comparable.CompareTo(y); else return 0; } } private OLVColumn column; private SortOrder sortOrder; private ModelObjectComparer secondComparer; #region IComparer Members #endregion } }