/* ListitemComparator.java
Purpose:
Description:
History:
Thu May 25 21:25:55 2006, Created by tomyeh
Copyright (C) 2006 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zul;
import java.util.Comparator;
import java.util.List;
/**
* A comparator used to compare {@link Listitem}, if not live data,
* or the data themselves, if live data.
*
* @author tomyeh
*/
public class ListitemComparator implements Comparator, java.io.Serializable {
/** The listheader (optinal). */
private final Listheader _header;
/** Column index. */
private int _index;
/** Ascending. */
private final boolean _asc;
/** Ignore case. */
private boolean _igcase;
/** Compares by value (instead of label) */
private boolean _byval;
/** Whether to treat null as the maximum value. */
private boolean _maxnull;
/** Compares with {@link Listitem#getValue}.
*
* <p>It assumes the value returned by {@link Listitem#getValue}
* implements Comparable.
*
* <p>Note: It assumes the ascending order and case-insensitive.
* If not, use {@link #ListitemComparator(int, boolean, boolean)}
* instead.
*/
public ListitemComparator() {
this(-1, true, true, false, false);
}
/** Compares with the column of the specified index.
*
* <p>0 for the first column, 1 for the second and so on
*
* <p>Note: -1 for {@link Listitem#getValue} and it assumes
* the value implements Comparable.
*
* <p>Note: It assumes the ascending order, case-insensitive and
* comparing the returned values of {@link Listcell#getLabel}.
* If not, use {@link #ListitemComparator(int, boolean, boolean, boolean)}
* instead.
*
* <p>A null value is considered as the minimum value.
*
* @param index which column to compare. If -1, {@link Listitem#getValue}
* is used.
*/
public ListitemComparator(int index) {
this(index, true, true, false, false);
}
/** Compares with the column of the specified index.
*
* <p>0 for the first column, 1 for the second and so on
*
* <p>Note: -1 for {@link Listitem#getValue} and it assumes
* the value implements Comparable.
*
* <p>Note: it compares the returned value of {@link Listcell#getLabel}.
* If you want to compare {@link Listcell#getValue}.,
* use {@link #ListitemComparator(int, boolean, boolean, boolean)}
* instead.
*
* <p>A null value is considered as the minimum value.
*
* @param index which column to compare. If -1, {@link Listitem#getValue}
* is used.
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
*/
public ListitemComparator(int index, boolean ascending, boolean ignoreCase) {
this(index, ascending, ignoreCase, false, false);
}
/** Compares with the column of the specified index.
*
* <p>0 for the first column, 1 for the second and so on
*
* <p>Note: -1 for {@link Listitem#getValue} and it assumes
* the value implements Comparable.
*
* <p>A null value is considered as the minimum value.
*
* @param index which column to compare. If -1, {@link Listitem#getValue}
* is used.
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
* @param byValue whether to compare {@link Listcell#getValue}.
* If false, it compares {@link Listcell#getLabel}.
* If true, it assumes the value returned by {@link Listcell#getValue}
* implements Comparable.
* It is ignored if the index is -1.
*/
public ListitemComparator(int index, boolean ascending, boolean ignoreCase, boolean byValue) {
this(index, ascending, ignoreCase, byValue, false);
}
/** Compares with the column of the specified index.
*
* <p>0 for the first column, 1 for the second and so on
*
* <p>Note: -1 for {@link Listitem#getValue} and it assumes
* the value implements Comparable.
*
* @param index which column to compare. If -1, {@link Listitem#getValue}
* is used.
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
* @param byValue whether to compare {@link Listcell#getValue}.
* If false, it compares {@link Listcell#getLabel}.
* If true, it assumes the value returned by {@link Listcell#getValue}
* implements Comparable.
* It is ignored if the index is -1.
* @param nullAsMax whether to consider null as the maximum value.
* If false, null is considered as the minimum value.
*/
public ListitemComparator(int index, boolean ascending, boolean ignoreCase, boolean byValue, boolean nullAsMax) {
_header = null;
_index = index;
_asc = ascending;
_igcase = ignoreCase;
_byval = byValue;
_maxnull = nullAsMax;
}
/** Compares with the column which the list header is at.
*
* <p>Note: it compares the returned value of {@link Listcell#getLabel}.
* If you want to compare {@link Listcell#getValue}.,
* use {@link #ListitemComparator(Listheader, boolean, boolean, boolean)}
* instead.
*
* <p>A null value is considered as the minimum value.
*
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
*/
public ListitemComparator(Listheader header, boolean ascending, boolean ignoreCase) {
this(header, ascending, ignoreCase, false, false);
}
/** Compares with the column which the list header is at.
*
* <p>A null value is considered as the minimum value.
*
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
* @param byValue whether to compare {@link Listcell#getValue}.
* If false, it compares {@link Listcell#getLabel}.
*/
public ListitemComparator(Listheader header, boolean ascending, boolean ignoreCase, boolean byValue) {
this(header, ascending, ignoreCase, byValue, false);
}
/** Compares with the column which the list header is at.
*
* @param ascending whether to sort as ascending (or descending).
* @param ignoreCase whether to sort case-insensitive
* @param byValue whether to compare {@link Listcell#getValue}.
* If false, it compares {@link Listcell#getLabel}.
* @param nullAsMax whether to consider null as the maximum value.
* If false, null is considered as the minimum value.
*/
public ListitemComparator(Listheader header, boolean ascending, boolean ignoreCase, boolean byValue,
boolean nullAsMax) {
_header = header;
_index = -1; //not decided yet
_asc = ascending;
_igcase = ignoreCase;
_byval = byValue;
_maxnull = nullAsMax;
}
/** Returns the listheader that this comparator is associated with, or null
* if not available.
*/
public Listheader getListheader() {
return _header;
}
/** Returns whether the order is ascending.
*/
public boolean isAscending() {
return _asc;
}
/** Returns whether to ignore case.
*/
public boolean shallIgnoreCase() {
return _igcase;
}
/** Returns whether to compare the returned value of {@link Listcell#getValue}
*/
public boolean byValue() {
return _byval;
}
//Comparator//
public int compare(Object o1, Object o2) {
final int index = _index < 0 && _header != null ? _header.getColumnIndex() : _index;
Object v1, v2;
if (o1 instanceof Listitem) { //not live data
final Listitem li1 = (Listitem) o1, li2 = (Listitem) o2;
if (index < 0) {
v1 = handleCase((Comparable) li1.getValue());
v2 = handleCase((Comparable) li2.getValue());
} else {
List lcs1 = li1.getChildren();
if (index >= lcs1.size())
v1 = null;
else {
final Listcell lc = (Listcell) lcs1.get(index);
v1 = handleCase(_byval ? lc.getValue() : lc.getLabel());
}
List lcs2 = li2.getChildren();
if (index >= lcs2.size())
v2 = null;
else {
final Listcell lc = (Listcell) lcs2.get(index);
v2 = handleCase(_byval ? lc.getValue() : lc.getLabel());
}
}
} else { //live data
v1 = handleCase(o1);
v2 = handleCase(o2);
}
if (v1 == null)
return v2 == null ? 0 : _maxnull ? 1 : -1;
if (v2 == null)
return _maxnull ? -1 : 1;
final int v = compareTo((Comparable) v1, v2);
return _asc ? v : -v;
}
@SuppressWarnings("unchecked")
private static int compareTo(Comparable v1, Object v2) {
return v1.compareTo(v2);
}
private Object handleCase(Object c) {
if (_igcase) {
if (c instanceof String)
return ((String) c).toUpperCase();
if (c instanceof Character)
return new Character(Character.toUpperCase(((Character) c).charValue()));
}
return c;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof ListitemComparator))
return false;
final ListitemComparator c = (ListitemComparator) o;
return c._index == _index && c._asc == _asc && c._igcase == _igcase;
}
public int hashCode() {
return _index ^ (_asc ? 1 : 5) ^ (_igcase ? 9 : 3);
}
public String toString() {
return "[Comparator " + _index + "-th col, asc:" + _asc + ']';
}
}