/* * Comparators.java * Copyright 2008 (C) Connor Petty <mistercpp2000@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on Feb 14, 2008, 11:23:02 PM */ package pcgen.util; import java.io.Serializable; import java.text.Collator; import java.util.Comparator; import java.util.Date; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.enumeration.StringKey; import pcgen.facade.core.InfoFacade; import pcgen.gui2.util.treetable.TreeTableNode; /** * * @author Connor Petty <mistercpp2000@gmail.com> */ @SuppressWarnings("unchecked") public final class Comparators { private Comparators() { } private static final ToStringComparator tSC = new ToStringComparator(); private static final ToStringIgnoreCaseComparator tSICC = new ToStringIgnoreCaseComparator(); private static final ToStringIgnoreCaseCollator tSICCol = new ToStringIgnoreCaseCollator(); private static final IntegerComparator iC = new IntegerComparator(); private static final NumberComparator nC = new NumberComparator(); private static final DateComparator dC = new DateComparator(); private static final HashCodeComparator hCC = new HashCodeComparator(); private static final TreeTableNodeComparator treeNodeComp = new TreeTableNodeComparator(); public static Comparator<Object> toStringComparator() { return tSC; } public static Comparator<Object> toStringIgnoreCaseComparator() { return tSICC; } public static Comparator<Object> toStringIgnoreCaseCollator() { return tSICCol; } /** * @return A comparator for use with the contents of tree table nodes. */ public static Comparator<Object> treeTableNodeComparator() { return treeNodeComp; } /** * TODO: perhaps keep instance references to commonly used InverseComparators? * @param comparator * @return new InverseComparator instance */ public static <T> Comparator<T> inverseComparator(Comparator<T> comparator) { if (comparator instanceof InverseComparator) { return ((InverseComparator<T>) comparator).getComparator(); } return new InverseComparator<>(comparator); } public static Comparator<Object> hashCodeComparator() { return hCC; } public static Comparator<Integer> integerComparator() { return iC; } public static Comparator<Number> numberComparator() { return nC; } public static Comparator<Date> dateComparator() { return dC; } public static Comparator<String> ignoreCaseStringComparator() { return String.CASE_INSENSITIVE_ORDER; } public static <T> Comparator<? super T> getComparatorFor(Class<T> c) { if (c == Integer.class) { return (Comparator<? super T>) integerComparator(); } else if (c.getSuperclass() == Number.class) { return (Comparator<? super T>) numberComparator(); } else if (c == Date.class) { return (Comparator<? super T>) dateComparator(); } else if (c == String.class) { return (Comparator<? super T>) ignoreCaseStringComparator(); } else if (c == TreeTableNode.class || c == InfoFacade.class || c.getSuperclass() == InfoFacade.class) { return treeTableNodeComparator(); } return toStringComparator(); } /** * A {@code Comparator} to compare objects as * {@code String}s. This is particularly useful for applications * such as maintaining a sorted {@code JComboBoxEx} and the like. * * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a> */ private static final class ToStringComparator implements Comparator<Object>, Serializable { @Override public int compare(Object o1, Object o2) { // Treat null as the empty string. return ((o1 == null) ? "" : o1.toString()).compareTo((o2 == null) ? "" : o2.toString()); } } /** * A {@code Comparator} to compare objects as * {@code String}s ignoring case. This is particularly useful * for applications such as maintaining a sorted * {@code JComboBoxEx} and the like. * * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a> */ private static final class ToStringIgnoreCaseComparator implements Comparator<Object>, Serializable { @Override public int compare(Object o1, Object o2) { // Treat null as the empty string. return ((o1 == null) ? "" : o1.toString()).compareToIgnoreCase((o2 == null) ? "" : o2.toString()); } } /** * A {@code Comparator} to compare tree table nodes. This respects SORTKEY for the contained object. */ private static final class TreeTableNodeComparator implements Comparator<Object>, Serializable { @Override public int compare(Object o1, Object o2) { String key1 = getSortKey(o1); String key2 = getSortKey(o2); final Collator collator = Collator.getInstance(); if (!key1.equals(key2)) { return collator.compare(key1, key2); } return collator.compare(String.valueOf(o1), String.valueOf(o2)); } private String getSortKey(Object obj1) { String key; if (obj1 == null) { key = ""; } else if (obj1 instanceof CDOMObject) { CDOMObject co = (CDOMObject) obj1; key = co.get(StringKey.SORT_KEY); if (key == null) { key = co.getDisplayName(); } } else if (obj1 instanceof SortKeyAware) { key = ((SortKeyAware) obj1).getSortKey(); } else { key = obj1.toString(); } return key; } } private static final class ToStringIgnoreCaseCollator implements Comparator<Object>, Serializable { private static final Collator collator = Collator.getInstance(); @Override public int compare(Object o1, Object o2) { String s1 = (o1 == null) ? "" : o1.toString(); String s2 = (o2 == null) ? "" : o2.toString(); return collator.compare(s1, s2); } } private static final class IntegerComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } } private static final class NumberComparator implements Comparator<Number> { @Override public int compare(Number o1, Number o2) { final double d1 = o1.doubleValue(); final double d2 = o2.doubleValue(); if (d1 < d2) { return -1; } if (d1 > d2) { return 1; } return 0; } } private static final class DateComparator implements Comparator<Date> { @Override public int compare(Date o1, Date o2) { final long n1 = o1.getTime(); final long n2 = o2.getTime(); if (n1 < n2) { return -1; } if (n1 > n2) { return 1; } return 0; } } private static final class HashCodeComparator implements Comparator<Object> { @Override public int compare(Object o1, Object o2) { return iC.compare(o1.hashCode(), o2.hashCode()); } } /** * * @param E */ private static final class InverseComparator<E> implements Comparator<E>, Serializable { private final Comparator<E> comparator; public InverseComparator(Comparator<E> comparator) { this.comparator = comparator; } public Comparator<E> getComparator() { return comparator; } @Override public int compare(E o1, E o2) { return -comparator.compare(o1, o2); } } }