]> err.no Git - sope/blob - sope-core/EOControl/EOSortOrdering.m
fixed resource lookup in SoProductResourceManager, added debug logs
[sope] / sope-core / EOControl / EOSortOrdering.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "EOSortOrdering.h"
24 #include "EOKeyValueCoding.h"
25 #include <EOControl/EONull.h>
26 #include "common.h"
27
28 #if GNU_RUNTIME
29 #  include <objc/objc.h>
30 #endif
31
32 #ifndef SEL_EQ
33 #  if GNU_RUNTIME
34 #    define SEL_EQ(sel1,sel2) sel_eq(sel1,sel2)
35 #  else
36 #    define SEL_EQ(sel1,sel2) (sel1 == sel2)
37 #  endif
38 #endif
39
40 #if !NeXT_RUNTIME
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:);
49 #endif
50
51 @implementation EOSortOrdering
52 /*"
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.
56 "*/
57
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];
61 }
62
63 /*" 
64   Initialize a sort-ordering object with the specified key and sort selector
65 "*/
66 - (id)initWithKey:(NSString *)_key selector:(SEL)_selector {
67   if ((self = [super init])) {
68     self->key      = [_key copyWithZone:[self zone]];
69     self->selector = _selector;
70   }
71   return self;
72 }
73
74 - (void)dealloc {
75   [self->key release];
76   [super dealloc];
77 }
78
79 /* accessors */
80
81 /*"
82   Returns the key the ordering sorts with.
83 "*/
84 - (NSString *)key {
85   return self->key;
86 }
87
88 /*"
89   Returns the selector the ordering sorts with.
90 "*/
91 - (SEL)selector {
92   return self->selector;
93 }
94
95 /* equality */
96
97 - (BOOL)isEqualToSortOrdering:(EOSortOrdering *)_sortOrdering {
98   if (!SEL_EQ([_sortOrdering selector], [self selector]))
99     return NO;
100   if (![[_sortOrdering key] isEqualToString:[self key]])
101     return NO;
102   return YES;
103 }
104 - (BOOL)isEqual:(id)_other {
105   if ([_other isKindOfClass:[EOSortOrdering class]])
106     return [self isEqualToSortOrdering:_other];
107
108   return NO;
109 }
110
111 /* remapping keys */
112
113 - (EOSortOrdering *)sortOrderingByApplyingKeyMap:(NSDictionary *)_map {
114   NSString *k;
115   
116   k = [_map objectForKey:self->key];
117   return [EOSortOrdering sortOrderingWithKey:(k ? k : self->key)
118                          selector:self->selector];
119 }
120
121 /* description */
122
123 - (NSString *)description {
124   return [NSString stringWithFormat:
125                      @"<0x%08X[%@]: key=%@ selector=%@>",
126                      self, NSStringFromClass([self class]),
127                      [self key], NSStringFromSelector([self selector])];
128 }
129
130 @end /* EOSortOrdering */
131
132 @implementation NSArray(EOSortOrdering)
133
134 /*" 
135   Sort the array using the sort-orderings contained in the argument. If no
136   orderings are given, a copy of self is returned.
137 "*/
138 - (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings {
139   NSMutableArray *m      = nil;
140   NSArray        *result = nil;
141   
142   if ([_orderings count] == 0)
143     return [[self copy] autorelease];
144   
145   m = [self mutableCopy];
146   [m sortUsingKeyOrderArray:_orderings];
147   result = [m copy];
148   [m release]; m = nil;
149   return [result autorelease];
150 }
151
152 @end /* NSArray(EOSortOrdering) */
153
154 @implementation NSMutableArray(EOSortOrdering)
155
156 typedef struct {
157   EOSortOrdering *orderings[10]; /* max depth 10 */
158   short          count;
159 } EOSortOrderingContext;
160
161 static EONull *null = nil;
162
163 static int keyOrderComparator(id o1, id o2, EOSortOrderingContext *context) {
164   short i;
165
166   for (i = 0; i < context->count; i++) {
167     NSString *key;
168     SEL      sel;
169     id       v1, v2;
170     int      (*ccmp)(id, SEL, id);
171     int      result;
172
173     key = [context->orderings[i] key];
174     sel = [context->orderings[i] selector];
175     
176     v1 = [o1 valueForKey:key];
177     v2 = [o2 valueForKey:key];
178
179     if (v1 == v2)
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);
189     else
190       result = (int)[v1 performSelector:sel withObject:v2];
191
192     if (result != NSOrderedSame)
193       return result;
194   }
195   return NSOrderedSame;
196 }
197
198 /*" 
199   Sort the array using the sort-orderings contained in the argument.
200 "*/
201 - (void)sortUsingKeyOrderArray:(NSArray *)_orderings {
202   NSEnumerator          *e        = nil;
203   EOSortOrdering        *ordering = nil;
204   EOSortOrderingContext ctx;
205   int                   i;
206   
207   NSAssert([_orderings count] < 10, @"max sort descriptor count is 10!");
208   
209   e = [_orderings objectEnumerator];
210   for (i = 0; (ordering = [e nextObject]) && (i < 10); i++)
211     ctx.orderings[i] = ordering;
212
213   ctx.count = i;
214
215   if (null == nil) null = [EONull null];
216   [self sortUsingFunction:(void *)keyOrderComparator context:&ctx];
217 }
218
219 @end /* NSMutableArray(EOSortOrdering) */
220
221 @implementation EONull(EOSortOrdering)
222
223 /*" 
224   Compares the null object, "nil" and "self" are considered of the same order,
225   otherwise null is considered of lower order.
226 "*/
227 - (int)compareAscending:(id)_object {
228   if (_object == self) return NSOrderedSame;
229   if (_object == nil)  return NSOrderedSame;
230   return NSOrderedDescending;
231 }
232
233 /*" 
234   Compares the null object, "nil" and "self" are considered of the same order,
235   otherwise null is considered of higher order.
236 "*/
237 - (int)compareDescending:(id)_object {
238   if (_object == self) return NSOrderedSame;
239   if (_object == nil)  return NSOrderedSame;
240   return NSOrderedAscending;
241 }
242
243 @end /* EONull(EOSortOrdering) */
244
245 @implementation NSNumber(EOSortOrdering)
246
247 static Class NumClass = Nil;
248
249 - (int)compareAscending:(id)_object {
250   if (_object == self) return NSOrderedSame;
251   if (NumClass == Nil) NumClass = [NSNumber class];
252   
253   if ([_object isKindOfClass:NumClass])
254     return [self compare:_object];
255   else
256     return [_object compareDescending:self];
257 }
258
259 - (int)compareDescending:(id)_object {
260   int result;
261   
262   result = [self compareAscending:_object];
263   
264   if (result == NSOrderedAscending)
265     return NSOrderedDescending;
266   else if (result == NSOrderedDescending)
267     return NSOrderedAscending;
268   else
269     return NSOrderedSame;
270 }
271
272 @end /* NSNumber(EOSortOrdering) */
273
274 @implementation NSString(EOSortOrdering)
275
276 - (int)compareAscending:(id)_object {
277   if (_object == self) return NSOrderedSame;
278   return [self compare:[_object stringValue]];
279 }
280 - (int)compareCaseInsensitiveAscending:(id)_object {
281   if (_object == self) return NSOrderedSame;
282   return [self caseInsensitiveCompare:[_object stringValue]];
283 }
284
285 - (int)compareDescending:(id)_object {
286   int result;
287   
288   if (_object == self) return NSOrderedSame;
289   
290   result = [self compareAscending:_object];
291   
292   if (result == NSOrderedAscending)
293     return NSOrderedDescending;
294   else if (result == NSOrderedDescending)
295     return NSOrderedAscending;
296   else
297     return NSOrderedSame;
298 }
299
300 - (int)compareCaseInsensitiveDescending:(id)_object {
301   int result;
302   
303   if (_object == self) return NSOrderedSame;
304   result = [self compareCaseInsensitiveAscending:_object];
305   
306   if (result == NSOrderedAscending)
307     return NSOrderedDescending;
308   else if (result == NSOrderedDescending)
309     return NSOrderedAscending;
310   else
311     return NSOrderedSame;
312 }
313
314 @end /* NSString(EOSortOrdering) */
315
316 @implementation NSDate(EOSortOrdering)
317
318 static Class DateClass = Nil;
319
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];
325 }
326 - (int)compareDescending:(id)_object {
327   int result;
328
329   if (_object == self) return NSOrderedSame;
330
331   if (DateClass == Nil) DateClass = [NSDate class];
332   if (![_object isKindOfClass:DateClass]) return NSOrderedDescending;
333   
334   result = [self compare:_object];
335   
336   if (result == NSOrderedAscending)
337     return NSOrderedDescending;
338   else if (result == NSOrderedDescending)
339     return NSOrderedAscending;
340   else
341     return NSOrderedSame;
342 }
343
344 @end /* NSDate(EOSortOrdering) */