package net.sf.jabref; import net.sf.jabref.gui.MainTableFormat; import java.util.Comparator; /** * * A comparator for BibtexEntry fields * * Initial Version: * * @author alver * @version Date: Oct 13, 2005 Time: 10:10:04 PM To * * Current Version: * * @author $Author: mortenalver $ * @version $Revision: 2734 $ ($Date: 2008-09-01 23:08:42 +0200 (Mo, 01 Sep 2008) $) * * TODO: Testcases * */ public class FieldComparator implements Comparator<BibtexEntry> { private String[] field; private String fieldName; boolean isNameField, isTypeHeader, isYearField, isMonthField, isNumeric; int multiplier; public FieldComparator(String field) { this(field, false); } public FieldComparator(String field, boolean reversed) { this.fieldName = field; this.field = field.split(MainTableFormat.COL_DEFINITION_FIELD_SEPARATOR); multiplier = reversed ? -1 : 1; isTypeHeader = this.field[0].equals(GUIGlobals.TYPE_HEADER); isNameField = (this.field[0].equals("author") || this.field[0].equals("editor")); isYearField = this.field[0].equals("year"); isMonthField = this.field[0].equals("month"); isNumeric = BibtexFields.isNumeric(this.field[0]); } public int compare(BibtexEntry e1, BibtexEntry e2) { Object f1, f2; if (isTypeHeader) { // Sort by type. f1 = e1.getType().getName(); f2 = e2.getType().getName(); } else { // If the field is author or editor, we rearrange names so they are // sorted according to last name. f1 = getField(e1); f2 = getField(e2); } /* * [ 1598777 ] Month sorting * * http://sourceforge.net/tracker/index.php?func=detail&aid=1598777&group_id=92314&atid=600306 */ int localMultiplier = multiplier; if (isMonthField) localMultiplier = -localMultiplier; // Catch all cases involving null: if (f1 == null) return f2 == null ? 0 : localMultiplier; if (f2 == null) return -localMultiplier; // Now we now that both f1 and f2 are != null if (isNameField) { f1 = AuthorList.fixAuthorForAlphabetization((String) f1); f2 = AuthorList.fixAuthorForAlphabetization((String) f2); } else if (isYearField) { /* * [ 1285977 ] Impossible to properly sort a numeric field * * http://sourceforge.net/tracker/index.php?func=detail&aid=1285977&group_id=92314&atid=600307 */ f1 = Util.toFourDigitYear((String) f1); f2 = Util.toFourDigitYear((String) f2); } else if (isMonthField) { /* * [ 1535044 ] Month sorting * * http://sourceforge.net/tracker/index.php?func=detail&aid=1535044&group_id=92314&atid=600306 */ f1 = new Integer(Util.getMonthNumber((String)f1)); f2 = new Integer(Util.getMonthNumber((String)f2)); } if (isNumeric) { Integer i1 = null, i2 = null; try { i1 = Integer.parseInt((String)f1); } catch (NumberFormatException ex) { // Parsing failed. } try { i2 = Integer.parseInt((String)f2); } catch (NumberFormatException ex) { // Parsing failed. } if (i2 != null && i1 != null) { // Ok, parsing was successful. Update f1 and f2: f1 = i1; f2 = i2; } else if (i1 != null) { // The first one was parseable, but not the second one. // This means we consider one < two f1 = i1; f2 = new Integer(i1.intValue()+1); } else if (i2 != null) { // The second one was parseable, but not the first one. // This means we consider one > two f2 = i2; f1 = new Integer(i2.intValue()+1); } // Else none of them were parseable, and we can fall back on comparing strings. } int result = 0; if ((f1 instanceof Integer) && (f2 instanceof Integer)) { result = (((Integer) f1).compareTo((Integer) f2)); } else if (f2 instanceof Integer) { Integer f1AsInteger = new Integer(f1.toString()); result = -((f1AsInteger).compareTo((Integer) f2)); } else if (f1 instanceof Integer) { Integer f2AsInteger = new Integer(f2.toString()); result = -(((Integer) f1).compareTo(f2AsInteger)); } else { String ours = ((String) f1).toLowerCase(), theirs = ((String) f2).toLowerCase(); result = ours.compareTo(theirs); } return result * localMultiplier; } private Object getField(BibtexEntry entry) { for (int i = 0; i < field.length; i++) { Object o = entry.getField(field[i]); if (o != null) return o; } return null; } /** * Returns the field this Comparator compares by. * * @return The field name. */ public String getFieldName() { return fieldName; } }