2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "EOSortOrdering.h"
24 #include "EOKeyValueCoding.h"
25 #include <EOControl/EONull.h>
29 # include <objc/objc.h>
34 # define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2)
36 # define SEL_EQ(sel1,sel2) (sel1 == sel2)
41 EOControl_DECLARE SEL EOCompareAscending =
42 @selector(compareAscending:);
43 EOControl_DECLARE SEL EOCompareDescending =
44 @selector(compareDescending:);
45 EOControl_DECLARE SEL EOCompareCaseInsensitiveAscending =
46 @selector(compareCaseInsensitiveAscending:);
47 EOControl_DECLARE SEL EOCompareCaseInsensitiveDescending =
48 @selector(compareCaseInsensitiveDescending:);
51 @implementation EOSortOrdering
53 This class specifies a sort-ordering as used with
54 EOFetchSpecification. It takes a key and a sort
55 selector which is used for comparision.
58 /*" Create a sort-ordering object with the specified key and sort selector "*/
59 + (EOSortOrdering *)sortOrderingWithKey:(NSString *)_key selector:(SEL)_sel {
60 return [[[self alloc] initWithKey:_key selector:_sel] autorelease];
64 Initialize a sort-ordering object with the specified key and sort selector
66 - (id)initWithKey:(NSString *)_key selector:(SEL)_selector {
67 if ((self = [super init])) {
68 self->key = [_key copyWithZone:[self zone]];
69 self->selector = _selector;
82 Returns the key the ordering sorts with.
89 Returns the selector the ordering sorts with.
92 return self->selector;
97 - (BOOL)isEqualToSortOrdering:(EOSortOrdering *)_sortOrdering {
98 if (!SEL_EQ([_sortOrdering selector], [self selector]))
100 if (![[_sortOrdering key] isEqualToString:[self key]])
104 - (BOOL)isEqual:(id)_other {
105 if ([_other isKindOfClass:[EOSortOrdering class]])
106 return [self isEqualToSortOrdering:_other];
113 - (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map {
116 k = [_map objectForKey:self->key];
117 return [EOSortOrdering sortOrderingWithKey:(k ? k : self->key)
118 selector:self->selector];
123 - (NSString *)description {
124 return [NSString stringWithFormat:
125 @"<0x%08X[%@]: key=%@ selector=%@>",
126 self, NSStringFromClass([self class]),
127 [self key], NSStringFromSelector([self selector])];
130 @end /* EOSortOrdering */
132 @implementation NSArray(EOSortOrdering)
135 Sort the array using the sort-orderings contained in the argument. If no
136 orderings are given, a copy of self is returned.
138 - (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings {
139 NSMutableArray *m = nil;
140 NSArray *result = nil;
142 if ([_orderings count] == 0)
143 return [[self copy] autorelease];
145 m = [self mutableCopy];
146 [m sortUsingKeyOrderArray:_orderings];
148 [m release]; m = nil;
149 return [result autorelease];
152 @end /* NSArray(EOSortOrdering) */
154 @implementation NSMutableArray(EOSortOrdering)
157 EOSortOrdering *orderings[10]; /* max depth 10 */
159 } EOSortOrderingContext;
161 static EONull *null = nil;
163 static int keyOrderComparator(id o1, id o2, EOSortOrderingContext *context) {
166 for (i = 0; i < context->count; i++) {
170 int (*ccmp)(id, SEL, id);
173 key = [context->orderings[i] key];
174 sel = [context->orderings[i] selector];
176 v1 = [o1 valueForKey:key];
177 v2 = [o2 valueForKey:key];
180 result = NSOrderedSame;
181 else if ((v1 == nil) || (v1 == null))
182 result = (sel == EOCompareAscending)
183 ? NSOrderedAscending : NSOrderedDescending;
184 else if ((v2 == nil) || (v2 == null))
185 result = (sel == EOCompareAscending)
186 ? NSOrderedDescending : NSOrderedAscending;
187 else if ((ccmp = (void *)[v1 methodForSelector:sel]))
188 result = ccmp(v1, sel, v2);
190 result = (int)[v1 performSelector:sel withObject:v2];
192 if (result != NSOrderedSame)
195 return NSOrderedSame;
199 Sort the array using the sort-orderings contained in the argument.
201 - (void)sortUsingKeyOrderArray:(NSArray *)_orderings {
202 NSEnumerator *e = nil;
203 EOSortOrdering *ordering = nil;
204 EOSortOrderingContext ctx;
207 NSAssert([_orderings count] < 10, @"max sort descriptor count is 10!");
209 e = [_orderings objectEnumerator];
210 for (i = 0; (ordering = [e nextObject]) && (i < 10); i++)
211 ctx.orderings[i] = ordering;
215 if (null == nil) null = [EONull null];
216 [self sortUsingFunction:(void *)keyOrderComparator context:&ctx];
219 @end /* NSMutableArray(EOSortOrdering) */
221 @implementation EONull(EOSortOrdering)
224 Compares the null object, "nil" and "self" are considered of the same order,
225 otherwise null is considered of lower order.
227 - (int)compareAscending:(id)_object {
228 if (_object == self) return NSOrderedSame;
229 if (_object == nil) return NSOrderedSame;
230 return NSOrderedDescending;
234 Compares the null object, "nil" and "self" are considered of the same order,
235 otherwise null is considered of higher order.
237 - (int)compareDescending:(id)_object {
238 if (_object == self) return NSOrderedSame;
239 if (_object == nil) return NSOrderedSame;
240 return NSOrderedAscending;
243 @end /* EONull(EOSortOrdering) */
245 @implementation NSNumber(EOSortOrdering)
247 static Class NumClass = Nil;
249 - (int)compareAscending:(id)_object {
250 if (_object == self) return NSOrderedSame;
251 if (NumClass == Nil) NumClass = [NSNumber class];
253 if ([_object isKindOfClass:NumClass])
254 return [self compare:_object];
256 return [_object compareDescending:self];
259 - (int)compareDescending:(id)_object {
262 result = [self compareAscending:_object];
264 if (result == NSOrderedAscending)
265 return NSOrderedDescending;
266 else if (result == NSOrderedDescending)
267 return NSOrderedAscending;
269 return NSOrderedSame;
272 @end /* NSNumber(EOSortOrdering) */
274 @implementation NSString(EOSortOrdering)
276 - (int)compareAscending:(id)_object {
277 if (_object == self) return NSOrderedSame;
278 return [self compare:[_object stringValue]];
280 - (int)compareCaseInsensitiveAscending:(id)_object {
281 if (_object == self) return NSOrderedSame;
282 return [self caseInsensitiveCompare:[_object stringValue]];
285 - (int)compareDescending:(id)_object {
288 if (_object == self) return NSOrderedSame;
290 result = [self compareAscending:_object];
292 if (result == NSOrderedAscending)
293 return NSOrderedDescending;
294 else if (result == NSOrderedDescending)
295 return NSOrderedAscending;
297 return NSOrderedSame;
300 - (int)compareCaseInsensitiveDescending:(id)_object {
303 if (_object == self) return NSOrderedSame;
304 result = [self compareCaseInsensitiveAscending:_object];
306 if (result == NSOrderedAscending)
307 return NSOrderedDescending;
308 else if (result == NSOrderedDescending)
309 return NSOrderedAscending;
311 return NSOrderedSame;
314 @end /* NSString(EOSortOrdering) */
316 @implementation NSDate(EOSortOrdering)
318 static Class DateClass = Nil;
320 - (int)compareAscending:(id)_object {
321 if (_object == self) return NSOrderedSame;
322 if (DateClass == Nil) DateClass = [NSDate class];
323 if (![_object isKindOfClass:DateClass]) return NSOrderedAscending;
324 return [self compare:_object];
326 - (int)compareDescending:(id)_object {
329 if (_object == self) return NSOrderedSame;
331 if (DateClass == Nil) DateClass = [NSDate class];
332 if (![_object isKindOfClass:DateClass]) return NSOrderedDescending;
334 result = [self compare:_object];
336 if (result == NSOrderedAscending)
337 return NSOrderedDescending;
338 else if (result == NSOrderedDescending)
339 return NSOrderedAscending;
341 return NSOrderedSame;
344 @end /* NSDate(EOSortOrdering) */