1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.control;
20
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import net.wotonomy.foundation.NSArray;
29 import net.wotonomy.foundation.NSMutableArray;
30 import net.wotonomy.foundation.NSSelector;
31
32 /***
33 * EOSortOrdering defines a sort key and operation.
34 * DisplayGroups use lists of EOSortOrdering to determine
35 * how to order their items.
36 *
37 * @author michael@mpowers.net
38 * @author $Author: cgruber $
39 * @version $Revision: 894 $
40 */
41 public class EOSortOrdering implements Serializable, EOKeyValueArchiving
42 {
43 /***
44 * Sorts items in ascending order.
45 */
46 public static final
47 NSSelector CompareAscending = new CompareAscendingComparator();
48
49 /***
50 * Sorts items in descending order.
51 */
52 public static final
53 NSSelector CompareDescending = new CompareDescendingComparator();
54
55 /***
56 * Sorts items' string representations in ascending order
57 * in a case insensitive manner.
58 */
59 public static final
60 NSSelector CompareCaseInsensitiveAscending =
61 new CompareCaseInsensitiveAscendingComparator();
62
63 /***
64 * Sorts items' string representations in descending order
65 * in a case insensitive manner.
66 */
67 public static final
68 NSSelector CompareCaseInsensitiveDescending =
69 new CompareCaseInsensitiveDescendingComparator();
70
71 protected String key;
72 protected NSSelector selector;
73
74 /***
75 * Factory-style constructor returns a new EOSortOrdering instance
76 * with the specified key and selector. Neither may be null.
77 */
78 public static EOSortOrdering sortOrderingWithKey(String key, NSSelector selector)
79 {
80 return new EOSortOrdering( key, selector );
81 }
82
83 /***
84 * Constructor creates an EOSortOrdering that uses the
85 * specified key and selector. Neither may be null.
86 */
87 public EOSortOrdering( String aKey, NSSelector aSelector )
88 {
89 key = aKey;
90 selector = aSelector;
91 }
92
93 /***
94 * Constructor creates an EOSortOrdering that uses the
95 * specified key and comparator. Neither may be null.
96 * Not in the spec.
97 */
98 public EOSortOrdering( String aKey, Comparator aComparator )
99 {
100 key = aKey;
101 selector = new NSSelector( aKey, aComparator );
102 }
103
104 /***
105 * Returns the property key.
106 */
107 public String key()
108 {
109 return key;
110 }
111
112 /***
113 * Returns the selector.
114 */
115 public NSSelector selector()
116 {
117 return selector;
118 }
119
120 public String toString()
121 {
122 return "[EOSortOrdering: key='"+key+"' selector='"+selector+"']";
123 }
124
125 public boolean equals( Object anObject )
126 {
127 if ( anObject instanceof EOSortOrdering )
128 {
129 EOSortOrdering x = (EOSortOrdering) anObject;
130 if ( selector().equals( x.selector() ) )
131 {
132 if ( key().equals( x.key() ) )
133 {
134 return true;
135 }
136 }
137 }
138 return false;
139 }
140
141 /***
142 * Sorts the specified list in place according to the specified
143 * list of EOSortOrderings. The items will be sorted first by the
144 * first ordering, and items with equal values for that property
145 * will be sorted by the next ordering, and so on.
146 */
147 public static void sortArrayUsingKeyOrderArray(
148 List anObjectList, List aSortOrderingList )
149 {
150 List keys = new ArrayList( aSortOrderingList );
151 Collections.reverse( keys );
152 Iterator it = keys.iterator();
153 EOSortOrdering sortOrdering;
154 while ( it.hasNext() )
155 {
156 sortOrdering = (EOSortOrdering) it.next();
157 Collections.sort( anObjectList,
158 new DelegatingComparator(
159 sortOrdering.key(), sortOrdering.selector() ) );
160 }
161 }
162
163 /***
164 * Sorts the specified list in place according to the specified
165 * list of EOSortOrderings. The items will be sorted first by the
166 * first ordering, and items with equal values for that property
167 * will be sorted by the next ordering, and so on.
168 */
169 public static NSArray sortedArrayUsingKeyOrderArray(
170 List anObjectList, List aSortOrderingList )
171 {
172 NSArray result = new NSMutableArray();
173 result.addAll( anObjectList );
174 sortArrayUsingKeyOrderArray( result, aSortOrderingList );
175 return result;
176 }
177
178 public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver arch) {
179 String k = (String)arch.decodeObjectForKey("key");
180 String sname = (String)arch.decodeObjectForKey("selectorName");
181 NSSelector sel = null;
182 if (sname.equals("compareAscending:"))
183 sel = CompareAscending;
184 else if (sname.equals("compareDescending:"))
185 sel = CompareDescending;
186 else if (sname.equals("compareCaseInsensitiveAscending:"))
187 sel = CompareCaseInsensitiveAscending;
188 else if (sname.equals("compareCaseInsensitiveDescending:"))
189 sel = CompareCaseInsensitiveAscending;
190 else {
191 if (sname.endsWith(":"))
192 sname = sname.substring(0, sname.length()-1);
193 sel = new NSSelector(sname, new Class[]{ Object.class });
194 }
195 return new EOSortOrdering(k, sel);
196 }
197
198 public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
199 arch.encodeObject("EOSortOrdering", "class");
200 arch.encodeObject(key(), "key");
201 if (selector.equals(CompareAscending))
202 arch.encodeObject("compareAscending:", "selectorName");
203 else if (selector.equals(CompareDescending))
204 arch.encodeObject("compareDescending:", "selectorName");
205 else if (selector.equals(CompareCaseInsensitiveAscending))
206 arch.encodeObject("compareCaseInsensitiveAscending:", "selectorName");
207 else if (selector.equals(CompareCaseInsensitiveAscending))
208 arch.encodeObject("compareCaseInsensitiveDescending:", "selectorName");
209 else
210 arch.encodeObject(selector.name() + ":", "selectorName");
211 }
212
213 private static class CompareAscendingComparator
214 extends NSSelector
215 {
216 public int compare(Object o1, Object o2)
217 {
218 if ( o1 instanceof Comparable )
219 {
220 if ( o2 instanceof Comparable )
221 {
222 return ((Comparable)o1).compareTo( o2 );
223 }
224 }
225
226
227
228 if ( o1 == null )
229 {
230 if ( o2 == null )
231 {
232 return 0;
233 }
234 else
235 {
236 return -1;
237 }
238 }
239 else
240 if ( o2 == null )
241 {
242 return 1;
243 }
244
245
246
247 return o1.toString().compareTo( o2.toString() );
248 }
249
250 public boolean equals(Object obj)
251 {
252 return ( this == obj );
253 }
254 }
255
256 private static class CompareDescendingComparator
257 extends CompareAscendingComparator
258 {
259 public int compare(Object o1, Object o2)
260 {
261 return -1 * super.compare( o1, o2 );
262 }
263 }
264
265 private static class CompareCaseInsensitiveAscendingComparator
266 extends NSSelector
267 {
268 public int compare(Object o1, Object o2)
269 {
270
271
272 if ( o1 == null )
273 {
274 if ( o2 == null )
275 {
276 return 0;
277 }
278 else
279 {
280 return -1;
281 }
282 }
283 else
284 if ( o2 == null )
285 {
286 return 1;
287 }
288
289 return o1.toString().toLowerCase().compareTo(
290 o2.toString().toLowerCase() );
291 }
292
293 public boolean equals(Object obj)
294 {
295 return ( this == obj );
296 }
297 }
298
299 private static class CompareCaseInsensitiveDescendingComparator
300 extends CompareCaseInsensitiveAscendingComparator
301 {
302 public int compare(Object o1, Object o2)
303 {
304 return -1 * super.compare( o1, o2 );
305 }
306 }
307
308 private static class DelegatingComparator implements Comparator
309 {
310 private String key;
311 private Comparator comparator;
312
313 public DelegatingComparator( String aKey, Comparator aComparator )
314 {
315 key = aKey;
316 comparator = aComparator;
317 }
318
319 public int compare(Object o1, Object o2)
320 {
321 Object v1, v2;
322 if ( o1 instanceof EOKeyValueCoding )
323 {
324 v1 = ((EOKeyValueCoding)o1).valueForKey( key );
325 }
326 else
327 {
328 v1 = EOKeyValueCodingSupport.valueForKey( o1, key );
329 }
330 if ( o2 instanceof EOKeyValueCoding )
331 {
332 v2 = ((EOKeyValueCoding)o2).valueForKey( key );
333 }
334 else
335 {
336 v2 = EOKeyValueCodingSupport.valueForKey( o2, key );
337 }
338 return comparator.compare( v1, v2 );
339 }
340
341 public boolean equals(Object obj)
342 {
343 return ( this == obj );
344 }
345 }
346
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406