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