2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "EOClassDescription.h"
23 #include "EOKeyValueCoding.h"
27 @implementation NSClassDescription(EOClassDescription)
31 - (NSString *)entityName {
34 - (NSString *)inverseForRelationshipKey:(NSString *)_key {
38 - (NSClassDescription *)classDescriptionForDestinationKey:(NSString *)_key {
42 /* object initialization */
44 - (id)createInstanceWithEditingContext:(id)_ec
45 globalID:(EOGlobalID *)_oid
51 - (void)awakeObject:(id)_object
52 fromFetchInEditingContext:(id)_ec
55 - (void)awakeObject:(id)_object
56 fromInsertionInEditingContext:(id)_ec
62 - (NSFormatter *)defaultFormatterForKey:(NSString *)_key {
65 - (NSFormatter *)defaultFormatterForKeyPath:(NSString *)_keyPath {
71 - (void)propagateDeleteForObject:(id)_object editingContext:(id)_ec {
74 @end /* NSClassDescription(EOClassDescription) */
76 @implementation EOClassDescription
79 static NSMapTable *entityToDesc = NULL;
80 static NSMapTable *classToDesc = NULL;
83 if (entityToDesc == NULL) {
84 entityToDesc = NSCreateMapTable(NSObjectMapKeyCallBacks,
85 NSObjectMapValueCallBacks,
88 if (classToDesc == NULL) {
89 classToDesc = NSCreateMapTable(NSObjectMapKeyCallBacks,
90 NSObjectMapValueCallBacks,
95 + (NSClassDescription *)classDescriptionForClass:(Class)_class
97 EOClassDescription *d;
100 NSAssert(_class != [EOGlobalID class],
101 @"classDescriptionForClass:EOGlobalID ???");
104 if ((d = NSMapGet(classToDesc, _class)))
107 [[NSNotificationCenter defaultCenter]
108 postNotificationName:
109 @"EOClassDescriptionNeededForClass"
112 return NSMapGet(classToDesc, _class);
115 + (NSClassDescription *)classDescriptionForEntityName:(NSString *)_entityName {
116 NSClassDescription *d;
118 if ((d = NSMapGet(entityToDesc, _entityName)))
121 [[NSNotificationCenter defaultCenter]
122 postNotificationName:
123 @"EOClassDescriptionNeededForEntityName"
126 return NSMapGet(entityToDesc, _entityName);
129 + (void)invalidateClassDescriptionCache {
130 NSResetMapTable(entityToDesc);
131 NSResetMapTable(classToDesc);
134 + (void)registerClassDescription:(NSClassDescription *)_clazzDesc
135 forClass:(Class)_class
137 NSString *entityName;
139 if (_clazzDesc == nil)
143 NSMapInsert(classToDesc, _class, _clazzDesc);
145 if ((entityName = [_clazzDesc entityName]))
146 NSMapInsert(entityToDesc, entityName, _clazzDesc);
151 - (NSString *)description {
152 return [NSString stringWithFormat:@"<%@[0x%p]: entity=%@>",
153 NSStringFromClass([self class]), self,
157 @end /* EOClassDescription */
159 @implementation NSObject(EOClassDescription)
161 - (NSClassDescription *)classDescriptionForDestinationKey:(NSString *)_key {
162 return [[self classDescription] classDescriptionForDestinationKey:_key];
165 /* object initialization */
167 - (id)initWithEditingContext:(id)_ec
168 classDescription:(NSClassDescription *)_classDesc
169 globalID:(EOGlobalID *)_oid
174 - (void)awakeFromFetchInEditingContext:(id)_ec {
175 [[self classDescription]
176 awakeObject:self fromFetchInEditingContext:_ec];
178 - (void)awakeFromInsertionInEditingContext:(id)_ec {
179 [[self classDescription]
180 awakeObject:self fromInsertionInEditingContext:_ec];
185 - (NSString *)entityName {
186 return [[self classDescription] entityName];
188 - (NSString *)inverseForRelationshipKey:(NSString *)_key {
189 return [[self classDescription] inverseForRelationshipKey:_key];
191 - (NSArray *)attributeKeys {
192 return [[self classDescription] attributeKeys];
195 - (BOOL)isToManyKey:(NSString *)_key {
196 return [[self toManyRelationshipKeys] containsObject:_key];
198 - (NSArray *)allPropertyKeys {
201 attrs = [self attributeKeys];
203 ? [attrs arrayByAddingObjectsFromArray:[self toOneRelationshipKeys]]
204 : [self toOneRelationshipKeys];
206 ? [attrs arrayByAddingObjectsFromArray:[self toManyRelationshipKeys]]
207 : [self toManyRelationshipKeys];
214 - (void)propagateDeleteWithEditingContext:(id)_ec {
215 [[self classDescription] propagateDeleteForObject:self editingContext:_ec];
218 @end /* NSObject(EOClassDescription) */
220 @implementation NSException(EOValidation)
222 + (NSException *)aggregateExceptionWithExceptions:(NSArray *)_exceptions {
225 e = [[self alloc] initWithName:@"EOAggregateException"
226 reason:@"several exceptions occured"
228 [NSDictionary dictionaryWithObject:_exceptions
229 forKey:@"exceptions"]];
230 return [e autorelease];
233 @end /* NSException(EOValidation) */
237 @implementation NSObject(EOSnapshots)
239 - (NSDictionary *)snapshot {
240 static NSNull *null = nil;
241 NSMutableDictionary *d;
246 if (null == nil) null = [NSNull null];
248 d = [[NSMutableDictionary alloc] initWithCapacity:64];
250 e = [[self attributeKeys] objectEnumerator];
251 while ((key = [e nextObject])) {
254 value = [self valueForKey:key];
255 value = (value == nil) ? (id)[null retain] : (id)[value copy];
256 [d setObject:value forKey:key];
257 [value release]; value = nil;
260 e = [[self toOneRelationshipKeys] objectEnumerator];
261 while ((key = [e nextObject])) {
264 value = [self valueForKey:key];
265 if (value == nil) value = [NSNull null];
267 [d setObject:value forKey:key];
270 e = [[self toManyRelationshipKeys] objectEnumerator];
271 while ((key = [e nextObject])) {
274 value = [self valueForKey:key];
276 value = [[NSNull null] retain];
279 value = [value shallowCopy];
281 [d setObject:value forKey:key];
282 [value release]; value = nil;
286 [d release]; d = nil;
287 return [r autorelease];
290 - (void)updateFromSnapshot:(NSDictionary *)_snapshot {
291 [self takeValuesFromDictionary:_snapshot];
294 - (NSDictionary *)changesFromSnapshot:(NSDictionary *)_snapshot {
295 /* not really correct, need to work on relationships */
296 static NSNull *null = nil;
297 NSMutableDictionary *diff;
301 if (null == nil) null = [NSNull null];
303 diff = [NSMutableDictionary dictionaryWithCapacity:32];
305 props = [[self allPropertyKeys] objectEnumerator];
306 while ((key = [props nextObject])) {
310 value = [self valueForKey:key];
311 svalue = [_snapshot objectForKey:key];
312 if (value == nil) value = null;
313 if (svalue == nil) svalue = null;
315 if (svalue != value) {
317 if ([self isToManyKey:key]) {
320 adiff[0] = [NSArray array];
321 adiff[1] = [NSArray array];
323 /* to be completed: calc real diff */
325 [diff setObject:[NSArray arrayWithObjects:adiff count:2] forKey:key];
328 [diff setObject:value forKey:key];
335 - (void)reapplyChangesFromDictionary:(NSDictionary *)_changes {
336 /* not really correct, need to work on relationships */
340 keys = [_changes keyEnumerator];
341 while ((key = [keys nextObject])) {
344 value = [_changes objectForKey:key];
346 if ([self isToManyKey:key]) {
349 NSMutableArray *current;
351 added = [value objectAtIndex:0];
352 deleted = [value objectAtIndex:1];
353 current = [[self valueForKey:key] mutableCopy];
355 if (added) [current addObjectsFromArray:added];
356 if (deleted) [current removeObjectsInArray:deleted];
358 [current release]; current = nil;
361 [self takeValue:value forKey:key];
363 [self takeValuesFromDictionary:_changes];
367 @end /* NSObject(EOSnapshots) */
371 @implementation NSObject(EORelationshipManipulation)
373 - (void)addObject:(id)_o toBothSidesOfRelationshipWithKey:(NSString *)_key {
377 revKey = [self inverseForRelationshipKey:_key];
378 isToMany = [self isToManyKey:_key];
380 self = [[self retain] autorelease];
381 _o = [[_o retain] autorelease];
384 /* watch out, likely to be buggy ! */
385 [self addObject:_o toPropertyWithKey:_key];
388 [self takeValue:_o forKey:_key];
391 /* add to the reverse object */
394 revIsToMany = [_o isToManyKey:revKey];
397 [_o addObject:self toPropertyWithKey:revKey];
399 [_o takeValue:self forKey:revKey];
402 - (void)removeObject:(id)_o fromBothSidesOfRelationshipWithKey:(NSString *)_key {
406 revKey = [self inverseForRelationshipKey:_key];
407 isToMany = [self isToManyKey:_key];
409 self = [[self retain] autorelease];
410 _o = [[_o retain] autorelease];
412 /* remove from this object */
415 [self removeObject:_o fromPropertyWithKey:_key];
417 [self takeValue:nil forKey:_key];
420 /* remove from reverse object */
423 revIsToMany = [_o isToManyKey:revKey];
426 [_o removeObject:self fromPropertyWithKey:revKey];
428 [_o takeValue:nil forKey:revKey];
432 - (void)addObject:(id)_object toPropertyWithKey:(NSString *)_key {
436 selname = [@"addTo" stringByAppendingString:[_key capitalizedString]];
437 sel = NSSelectorFromString(selname);
439 if ([self respondsToSelector:sel])
440 [self performSelector:sel withObject:_object];
444 v = [self valueForKey:_key];
446 if ([self isToManyKey:_key]) {
447 /* to-many relationship */
449 [self takeValue:[NSArray arrayWithObject:_object] forKey:_key];
451 else if (![v containsObject:_object]) {
452 if ([v respondsToSelector:@selector(addObject:)])
453 [v addObject:_object];
455 v = [v arrayByAddingObject:_object];
456 [self takeValue:v forKey:_key];
461 /* to-one relationship */
463 [self takeValue:v forKey:_key];
467 - (void)removeObject:(id)_object fromPropertyWithKey:(NSString *)_key {
471 selname = [@"removeFrom" stringByAppendingString:[_key capitalizedString]];
472 sel = NSSelectorFromString(selname);
474 if ([self respondsToSelector:sel])
475 [self performSelector:sel withObject:_object];
479 v = [self valueForKey:_key];
481 if ([self isToManyKey:_key]) {
482 /* to-many relationship */
486 else if (![v containsObject:_object]) {
487 if ([v respondsToSelector:@selector(addObject:)])
488 [v removeObject:_object];
491 [v removeObject:_object];
492 [self takeValue:v forKey:_key];
493 [v release]; v = nil;
498 /* to-one relationship */
499 [self takeValue:nil forKey:_key];
504 @end /* NSObject(EORelationshipManipulation) */
506 /* shallow array copying */
508 @implementation NSArray(ShallowCopy)
516 objects = calloc(cc + 1, sizeof(id));
518 for (i = 0; i < cc; i++)
519 objects[i] = [self objectAtIndex:i];
521 a = [[NSArray alloc] initWithObjects:objects count:cc];
523 if (objects) free(objects);
528 @end /* NSArray(ShallowCopy) */