c976b9ce2d5d41e6e1033009429b638ca94d3f53
[debian/jabref.git] / src / java / net / sf / jabref / FieldComparator.java
1 package net.sf.jabref;
2
3 import java.util.Comparator;
4
5 /**
6  * 
7  * A comparator for BibtexEntry fields
8  * 
9  * Initial Version:
10  * 
11  * @author alver
12  * @version Date: Oct 13, 2005 Time: 10:10:04 PM To
13  * 
14  * Current Version:
15  * 
16  * @author $Author: coezbek $
17  * @version $Revision: 2488 $ ($Date: 2007-11-14 01:25:31 +0100 (Wed, 14 Nov 2007) $)
18  * 
19  * TODO: Testcases
20  * 
21  */
22 public class FieldComparator implements Comparator<BibtexEntry> {
23
24         String field;
25
26         boolean isNameField, isTypeHeader, isYearField, isMonthField, isNumeric;
27
28         int multiplier;
29
30         public FieldComparator(String field) {
31                 this(field, false);
32         }
33
34         public FieldComparator(String field, boolean reversed) {
35                 this.field = field;
36                 multiplier = reversed ? -1 : 1;
37                 isTypeHeader = field.equals(GUIGlobals.TYPE_HEADER);
38
39                 isNameField = (field.equals("author") || field.equals("editor"));
40                 isYearField = field.equals("year");
41                 isMonthField = field.equals("month");
42         isNumeric = BibtexFields.isNumeric(field);
43     }
44
45         public int compare(BibtexEntry e1, BibtexEntry e2) {
46                 Object f1, f2;
47
48                 if (isTypeHeader) {
49                         // Sort by type.
50                         f1 = e1.getType().getName();
51                         f2 = e2.getType().getName();
52                 } else {
53
54                         // If the field is author or editor, we rearrange names so they are
55                         // sorted according to last name.
56                         f1 = e1.getField(field);
57                         f2 = e2.getField(field);
58                 }
59
60                 /*
61                  * [ 1598777 ] Month sorting
62                  * 
63                  * http://sourceforge.net/tracker/index.php?func=detail&aid=1598777&group_id=92314&atid=600306
64                  */
65                 int localMultiplier = multiplier;
66                 if (isMonthField)
67                         localMultiplier = -localMultiplier;
68                 
69                 // Catch all cases involving null:
70                 if (f1 == null)
71                         return f2 == null ? 0 : localMultiplier;
72
73                 if (f2 == null)
74                         return -localMultiplier;
75
76                 // Now we now that both f1 and f2 are != null
77                 if (isNameField) {
78                         f1 = AuthorList.fixAuthorForAlphabetization((String) f1);
79                         f2 = AuthorList.fixAuthorForAlphabetization((String) f2);
80                 } else if (isYearField) {
81                         /*
82                          * [ 1285977 ] Impossible to properly sort a numeric field
83                          * 
84                          * http://sourceforge.net/tracker/index.php?func=detail&aid=1285977&group_id=92314&atid=600307
85                          */
86                         f1 = Util.toFourDigitYear((String) f1);
87                         f2 = Util.toFourDigitYear((String) f2);
88                 } else if (isMonthField) {
89                         /*
90                          * [ 1535044 ] Month sorting
91                          * 
92                          * http://sourceforge.net/tracker/index.php?func=detail&aid=1535044&group_id=92314&atid=600306
93                          */
94                         f1 = new Integer(Util.getMonthNumber((String)f1));                      
95                         f2 = new Integer(Util.getMonthNumber((String)f2));
96                 }
97
98         if (isNumeric) {
99             Integer i1 = null, i2 = null;
100             try {
101                 i1 = Integer.parseInt((String)f1);
102             } catch (NumberFormatException ex) {
103                 // Parsing failed.
104             }
105
106             try {
107                 i2 = Integer.parseInt((String)f2);
108             } catch (NumberFormatException ex) {
109                 // Parsing failed.
110             }
111
112             if (i2 != null && i1 != null) {
113                 // Ok, parsing was successful. Update f1 and f2:
114                 f1 = i1;
115                 f2 = i2;
116             } else if (i1 != null) {
117                 // The first one was parseable, but not the second one.
118                 // This means we consider one < two
119                 f1 = i1;
120                 f2 = new Integer(i1.intValue()+1);
121             } else if (i2 != null) {
122                 // The second one was parseable, but not the first one.
123                 // This means we consider one > two
124                 f2 = i2;
125                 f1 = new Integer(i2.intValue()+1);
126             }
127             // Else none of them were parseable, and we can fall back on comparing strings.    
128         }
129
130         int result = 0;
131                 if ((f1 instanceof Integer) && (f2 instanceof Integer)) {
132                         result = (((Integer) f1).compareTo((Integer) f2));
133                 } else if (f2 instanceof Integer) {
134                         Integer f1AsInteger = new Integer(f1.toString());
135                         result = -((f1AsInteger).compareTo((Integer) f2));
136                 } else if (f1 instanceof Integer) {
137                         Integer f2AsInteger = new Integer(f2.toString());
138                         result = -(((Integer) f1).compareTo(f2AsInteger));
139                 } else {
140                         String ours = ((String) f1).toLowerCase(), theirs = ((String) f2).toLowerCase();
141             result = ours.compareTo(theirs);
142                 }
143
144                 return result * localMultiplier;
145         }
146
147         /**
148          * Returns the field this Comparator compares by.
149          * 
150          * @return The field name.
151          */
152         public String getFieldName() {
153                 return field;
154         }
155 }