/[gnustep]/gnustep/dev-libs/gdl2/EOControl/EOClassDescription.m
ViewVC logotype

Contents of /gnustep/dev-libs/gdl2/EOControl/EOClassDescription.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (show annotations) (download)
Mon Sep 29 19:23:58 2003 UTC (20 years, 6 months ago) by ayers
Branch: MAIN
Changes since 1.15: +6 -6 lines
	* EOControl/EOClassDescription.m
	(+[EOClassDescription initialize]): Initialize model group
	after callback tables are initilized.

1 /**
2 EOClassDescription.m <title>EOClassDescription Class</title>
3
4 Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
5
6 Author: Mirko Viviani <mirko.viviani@rccr.cremona.it>
7 Date: February 2000
8
9 Author: Manuel Guesdon <mguesdon@orange-concept.com>
10 Date: November 2001
11
12 $Revision: 1.15 $
13 $Date: 2003/08/25 20:01:58 $
14
15 <abstract></abstract>
16
17 This file is part of the GNUstep Database Library.
18
19 <license>
20 This library is free software; you can redistribute it and/or
21 modify it under the terms of the GNU Library General Public
22 License as published by the Free Software Foundation; either
23 version 2 of the License, or (at your option) any later version.
24
25 This library is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 Library General Public License for more details.
29
30 You should have received a copy of the GNU Library General Public
31 License along with this library; see the file COPYING.LIB.
32 If not, write to the Free Software Foundation,
33 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 </license>
35 **/
36
37 #include "config.h"
38
39 RCS_ID("$Id: EOClassDescription.m,v 1.15 2003/08/25 20:01:58 ayers Exp $")
40
41 #ifndef NeXT_Foundation_LIBRARY
42 #include <Foundation/NSString.h>
43 #include <Foundation/NSArray.h>
44 #include <Foundation/NSDictionary.h>
45 #include <Foundation/NSEnumerator.h>
46 #include <Foundation/NSNotification.h>
47 #include <Foundation/NSFormatter.h>
48 #include <Foundation/NSException.h>
49 #include <Foundation/NSMapTable.h>
50 #include <Foundation/NSZone.h>
51 #include <Foundation/NSObjCRuntime.h>
52 #include <Foundation/NSDebug.h>
53 #else
54 #include <Foundation/Foundation.h>
55 #endif
56
57 #ifndef GNUSTEP
58 #include <GNUstepBase/GNUstep.h>
59 #endif
60
61 #include <EOControl/EOClassDescription.h>
62 #include <EOControl/EOKeyValueCoding.h>
63 #include <EOControl/EONull.h>
64 #include <EOControl/EOEditingContext.h>
65 #include <EOControl/EOCheapArray.h>
66 #include <EOControl/EONSAddOns.h>
67 #include <EOControl/EODebug.h>
68
69 // NOTE: (stephane@sente.ch) Should we subclass NSClassDescription?
70
71 /*
72 d.ayers@inode.at: Yes, once we wish to support code written for
73 for EOF > WO4.5. No, for now because we don't have direct access
74 to the NSMapTable of base/Foundation so we would loose efficiency
75 and gain no real benefit.
76 */
77
78 @interface NSObject (SupressCompilerWarnings)
79 +(id)defaultGroup;
80 @end
81
82 @implementation EOClassDescription
83
84 NSString *EOClassDescriptionNeededNotification
85 = @"EOClassDescriptionNeededNotification";
86
87 NSString *EOClassDescriptionNeededForClassNotification
88 = @"EOClassDescriptionNeededForClassNotification";
89
90 NSString *EOClassDescriptionNeededForEntityNameNotification
91 = @"EOClassDescriptionNeededForEntityNameNotification";
92
93 NSString *EOValidationException = @"EOValidationException";
94 NSString *EOAdditionalExceptionsKey = @"EOAdditionalExceptionsKey";
95 NSString *EOValidatedObjectUserInfoKey = @"EOValidatedObjectUserInfoKey";
96 NSString *EOValidatedPropertyUserInfoKey = @"EOValidatedPropertyUserInfoKey";
97
98 /*
99 * Globals
100 */
101
102 static NSMapTable *classDescriptionForEntity = NULL;
103 static NSMapTable *classDescriptionForClass = NULL;
104 static id classDelegate = nil;
105
106 + (void)initialize
107 {
108 if (self == [EOClassDescription class])
109 {
110 Class cls = NSClassFromString(@"EOModelGroup");
111
112 classDescriptionForClass = NSCreateMapTable(NSObjectMapKeyCallBacks,
113 NSObjectMapValueCallBacks,
114 32);
115
116 classDescriptionForEntity = NSCreateMapTable(NSObjectMapKeyCallBacks,
117 NSObjectMapValueCallBacks,
118 32);
119 if (cls != Nil)
120 [cls defaultGroup]; // Insure correct initialization.
121
122 }
123 }
124
125
126 /*
127 * Methods
128 */
129
130 + (id)classDelegate
131 {
132 id delegate;
133 NSLock *lock = GDL2GlobalLock();
134
135 if (lock == nil)
136 {
137 delegate = classDelegate;
138 }
139 else
140 {
141 [lock lock];
142 delegate = classDelegate;
143 if (delegate != nil)
144 {
145 AUTORELEASE(RETAIN(delegate));
146 }
147 [lock unlock];
148 }
149
150 return delegate;
151 }
152
153 + (EOClassDescription *)classDescriptionForClass:(Class)aClass
154 {
155 EOClassDescription *classDescription;
156
157 EOFLOGObjectFnStart();
158
159 NSDebugMLLog(@"gsdb", @"aClass=%@", aClass);
160 NSAssert(aClass, @"No class");
161 NSDebugMLLog(@"gsdb", @"class name=%s", GSNameFromClass(aClass));
162
163 classDescription = NSMapGet(classDescriptionForClass, aClass);
164
165 NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription);
166 if (!classDescription)
167 {
168 [[NSNotificationCenter defaultCenter]
169 postNotificationName: EOClassDescriptionNeededForClassNotification
170 object: aClass];
171
172 classDescription = NSMapGet(classDescriptionForClass, aClass);
173 NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription);
174
175 if (!classDescription)
176 {
177 NSLog(@"Warning: No class description for class named: %s",
178 GSNameFromClass(aClass));
179 }
180 }
181
182 EOFLOGObjectFnStop();
183
184 return classDescription;
185 }
186
187 + (EOClassDescription *)classDescriptionForEntityName: (NSString *)entityName
188 {
189 EOClassDescription* classDescription;
190
191 EOFLOGObjectFnStart();
192
193 NSDebugMLLog(@"gsdb", @"entityName=%@", entityName);
194
195 classDescription = NSMapGet(classDescriptionForEntity, entityName);
196 NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription);
197
198 if (!classDescription)
199 {
200 [[NSNotificationCenter defaultCenter]
201 postNotificationName: EOClassDescriptionNeededForEntityNameNotification
202 object: entityName];
203
204 classDescription = NSMapGet(classDescriptionForEntity, entityName);
205 NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription);
206
207 if (!classDescription)
208 {
209 NSLog(@"Warning: No class description for entity named: %@",
210 entityName);
211 }
212 }
213
214 EOFLOGObjectFnStop();
215
216 return classDescription;
217 }
218
219 + (void)invalidateClassDescriptionCache
220 {
221 NSResetMapTable(classDescriptionForClass);
222 NSResetMapTable(classDescriptionForEntity);
223 }
224
225 + (void)registerClassDescription: (EOClassDescription *)description
226 forClass: (Class)aClass
227 {
228 NSString *entityName;
229
230 EOFLOGObjectFnStart();
231
232 NSAssert(description, @"No class description");
233 NSAssert(aClass, @"No class");
234 NSDebugMLLog(@"gsdb", @"description=%@", description);
235
236 entityName = [description entityName];
237 //NSAssert(entityName,@"No Entity Name");
238 NSDebugMLLog(@"gsdb", @"entityName=%@", entityName);
239
240 NSMapInsert(classDescriptionForClass, aClass, description);
241 if (entityName)
242 {
243 NSMapInsert(classDescriptionForEntity, entityName, description);
244 }
245 NSDebugMLLog(@"gsdb", @"end");
246
247 EOFLOGObjectFnStop();
248 }
249
250 + (void)setClassDelegate:(id)delegate
251 {
252 EOFLOGObjectFnStart();
253
254 NSDebugMLLog(@"gsdb",@"delegate %p=%@", delegate, delegate);
255 classDelegate = delegate;
256
257 EOFLOGObjectFnStop();
258 }
259
260 - (NSArray *)attributeKeys
261 {
262 return nil;
263 }
264
265 - (void)awakeObject: (id)object
266 fromFetchInEditingContext: (EOEditingContext *)anEditingContext
267 {
268 //OK
269 //nothing to do
270 }
271
272 - (void)awakeObject: (id)object
273 fromInsertionInEditingContext: (EOEditingContext *)anEditingContext
274 {
275 //Near OK
276 NSArray *toManyRelationshipKeys = nil;
277 int toManyCount = 0;
278
279 EOFLOGObjectFnStart();
280
281 toManyRelationshipKeys = [self toManyRelationshipKeys];
282 toManyCount = [toManyRelationshipKeys count];
283
284 if (toManyCount > 0)
285 {
286 int i;
287
288 for (i = 0; i < toManyCount; i++)
289 {
290 id key = [toManyRelationshipKeys objectAtIndex: i];
291 id value = [object storedValueForKey: key];
292 NSDebugMLLog(@"gsdb", @"key=%@ value=%@",key,value);
293
294 if (value)
295 {
296 //Do nothing ??
297 }
298 else
299 {
300 [object takeStoredValue:[EOCheapCopyMutableArray
301 arrayWithCapacity: 2]
302 forKey: key];
303 }
304 }
305 }
306 EOFLOGObjectFnStop();
307 }
308
309 - (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey
310 {
311 return nil;
312 }
313
314 - (id)createInstanceWithEditingContext: (EOEditingContext *)anEditingContext
315 globalID: (EOGlobalID *)globalID
316 zone: (NSZone *)zone
317 {
318 EOFLOGObjectFnStart();
319 EOFLOGObjectFnStop();
320
321 return nil;
322 }
323
324 - (NSFormatter *)defaultFormatterForKey: (NSString *)key
325 {
326 return nil;
327 }
328
329 - (NSFormatter *)defaultFormatterForKeyPath: (NSString *)keyPath
330 {
331 return nil; //TODO
332 }
333
334 - (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey
335 {
336 //OK
337 EOFLOGObjectFnStart();
338 EOFLOGObjectFnStop();
339
340 return EODeleteRuleNullify;
341 }
342
343 - (NSString *)displayNameForKey: (NSString *)key
344 {
345 const char *s, *ckey = [key cString];
346 NSMutableString *str = [NSMutableString stringWithCapacity:[key length]];
347 char c;
348 BOOL init = NO;
349
350 s = ckey;
351
352 while (*s)
353 {
354 if (init && s == ckey && islower(*s))
355 {
356 c = toupper(*s);
357 [str appendString: [NSString stringWithCString: &c length: 1]];
358 }
359 else if (isupper(*s) && s != ckey)
360 {
361 [str appendString: [NSString stringWithCString: ckey
362 length: s - ckey]];
363 [str appendString: @" "];
364 ckey = s;
365 }
366
367 init = NO;
368 s++;
369 }
370
371 if (s != ckey)
372 [str appendString: [NSString stringWithCString: ckey length: s - ckey]];
373
374 return AUTORELEASE([key copy]);
375 }
376
377 - (NSString *)entityName
378 {
379 //OK
380 return nil;
381 }
382
383 - (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey
384 {
385 return nil;
386 }
387
388 - (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey
389 {
390 return NO;
391 }
392
393 - (void)propagateDeleteForObject: (id)object
394 editingContext: (EOEditingContext *)context
395 {
396 NSArray *toRelArray;
397 NSEnumerator *toRelEnum;
398 NSString *key; //, *inverseKey = nil;
399 id destination = nil;
400 id classDelegate;
401
402 EOFLOGObjectFnStart();
403
404 NSDebugMLLog(@"gsdb",@"object %p=%@", object, object);
405
406 classDelegate = [[self class] classDelegate];
407
408 NSDebugMLLog(@"gsdb", @"classDelegate%p=%@",
409 classDelegate,
410 classDelegate);
411
412 toRelArray = [object toOneRelationshipKeys];
413 toRelEnum = [toRelArray objectEnumerator];
414
415 while ((key = [toRelEnum nextObject]))
416 {
417 BOOL shouldPropagate = YES;
418
419 NSDebugMLLog(@"gsdb", @"ToOne key=%@", key);
420
421 if (classDelegate)
422 shouldPropagate = [classDelegate shouldPropagateDeleteForObject: object
423 inEditingContext: context
424 forRelationshipKey: key];
425
426 NSDebugMLLog(@"gsdb", @"ToOne key=%@ shouldPropagate=%s", key,
427 (shouldPropagate ? "YES" : "NO"));
428
429 if (shouldPropagate)
430 {
431 destination = [object storedValueForKey: key];
432 NSDebugMLLog(@"gsdb", @"destination %p=%@",
433 destination, destination);
434
435 if (destination)
436 {
437 EODeleteRule deleteRule = [object deleteRuleForRelationshipKey:
438 key];
439
440 NSDebugMLLog(@"gsdb", @"deleteRule=%d", (int)deleteRule);
441
442 switch (deleteRule)
443 {
444 case EODeleteRuleNullify:
445 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleNullify");
446
447 [object removeObject: destination
448 fromBothSidesOfRelationshipWithKey: key];
449 /*
450 [object takeValue:nil
451 forKey:key];
452 inverseKey = [object inverseForRelationshipKey:key];
453 NSDebugMLLog(@"gsdb",@"inverseKey=%@",inverseKey);
454
455 if (inverseKey)
456 // p.ex. : the statement [employee inverseForRelationshipKey:@"department"] --> returns "employees"
457 [destination removeObject:object
458 fromPropertyWithKey:inverseKey];
459 */
460 break;
461
462 case EODeleteRuleCascade:
463 //OK
464 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleCascade");
465 [object removeObject: destination
466 fromBothSidesOfRelationshipWithKey: key];
467 [context deleteObject: destination];
468 [destination propagateDeleteWithEditingContext: context];
469 break;
470
471 case EODeleteRuleDeny:
472 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleDeny");
473 // TODO don't know how to do yet, if raise an exception
474 // or something else.
475 NSEmitTODO();
476 [self notImplemented: _cmd];
477 break;
478
479 case EODeleteRuleNoAction:
480 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleNoAction");
481 break;
482 }
483 }
484 }
485 }
486
487 toRelArray = [self toManyRelationshipKeys];
488 toRelEnum = [toRelArray objectEnumerator];
489
490 while ((key = [toRelEnum nextObject]))
491 {
492 BOOL shouldPropagate = YES;
493
494 NSDebugMLLog(@"gsdb", @"ToMany key=%@", key);
495
496 if (classDelegate)
497 shouldPropagate = [classDelegate shouldPropagateDeleteForObject: object
498 inEditingContext: context
499 forRelationshipKey: key];
500 NSDebugMLLog(@"gsdb", @"ToMany key=%@ shouldPropagate=%s", key,
501 (shouldPropagate ? "YES" : "NO"));
502
503 if (shouldPropagate)
504 {
505 NSArray *toManyArray;
506 EODeleteRule deleteRule;
507
508 toManyArray = [object valueForKey: key];
509 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray);
510
511 deleteRule = [object deleteRuleForRelationshipKey: key];
512 NSDebugMLLog(@"gsdb", @"deleteRule=%d", (int)deleteRule);
513
514 switch (deleteRule)
515 {
516 case EODeleteRuleNullify:
517 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleNullify");
518 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray,
519 toManyArray);
520
521 while ((destination = [toManyArray lastObject]))
522 {
523 NSDebugMLLog(@"gsdb", @"destination %p=%@", destination,
524 destination);
525
526 [object removeObject: destination
527 fromBothSidesOfRelationshipWithKey: key];
528 /*
529 inverseKey = [self inverseForRelationshipKey:key];
530 NSDebugMLLog(@"gsdb",@"inverseKey=%@",inverseKey);
531
532 if (inverseKey)
533 [destination removeObject:object
534 fromPropertyWithKey:inverseKey];
535 */
536 }
537 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@",
538 toManyArray, toManyArray);
539 break;
540
541 case EODeleteRuleCascade:
542 //OK
543 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleCascade");
544 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@",
545 toManyArray, toManyArray);
546
547 while ((destination = [toManyArray lastObject]))
548 {
549 NSDebugMLLog(@"gsdb", @"destination %p=%@",
550 destination, destination);
551
552 [object removeObject: destination
553 fromBothSidesOfRelationshipWithKey: key];
554 [context deleteObject: destination];
555 [destination propagateDeleteWithEditingContext: context];
556 }
557 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@",
558 toManyArray, toManyArray);
559 break;
560
561 case EODeleteRuleDeny:
562 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleDeny");
563 NSDebugMLLog(@"gsdb", @"toManyArray %p=%@",
564 toManyArray, toManyArray);
565 if ([toManyArray count] > 0)
566 {
567 // TODO don't know how to do yet, if raise an exception
568 // or something else.
569 NSEmitTODO();
570 [self notImplemented: _cmd];
571 }
572 break;
573
574 case EODeleteRuleNoAction:
575 EOFLOGObjectLevel(@"gsdb", @"EODeleteRuleNoAction");
576 break;
577 }
578 }
579 }
580
581 EOFLOGObjectFnStop();
582 }
583
584 - (NSArray *)toManyRelationshipKeys
585 {
586 //OK
587 return nil;
588 }
589
590 - (NSArray *)toOneRelationshipKeys
591 {
592 //OK
593 return nil;
594 }
595
596 - (EORelationship *)relationshipNamed:(NSString *)relationshipName
597 {
598 //OK
599 return nil;
600 }
601
602 - (EORelationship *)anyRelationshipNamed:(NSString *)relationshipNamed
603 {
604 return nil;
605 }
606
607 - (NSString *)userPresentableDescriptionForObject:(id)anObject
608 {
609 NSArray *attrArray = [self attributeKeys];
610 NSEnumerator *attrEnum = [attrArray objectEnumerator];
611 NSMutableString *values = [NSMutableString stringWithCapacity:
612 4 * [attrArray count]];
613 NSString *key;
614 BOOL init = YES;
615
616 attrEnum = [attrArray objectEnumerator];
617
618 while ((key = [attrEnum nextObject]))
619 {
620 if (!init)
621 [values appendString: @","];
622
623 [values appendString: [[self valueForKey: key] description]];
624 init = NO;
625 }
626
627 return values;
628 }
629
630 - (NSException *)validateObjectForDelete: (id)object
631 {
632 return nil;
633 }
634
635 - (NSException *)validateObjectForSave:(id)object
636 {
637 return nil;
638 }
639
640 - (NSException *)validateValue: (id *)valueP
641 forKey: (NSString *)key
642 {
643 return nil;
644 }
645
646 @end
647
648 @implementation EOClassDescription (Deprecated)
649
650 + (void)setDelegate: (id)delegate
651 {
652 EOFLOGObjectFnStart();
653
654 NSDebugMLLog(@"gsdb", @"delegate %p=%@", delegate, delegate);
655
656 [EOClassDescription setClassDelegate: delegate];
657
658 EOFLOGObjectFnStop();
659 }
660
661 + (id)delegate
662 {
663 return [EOClassDescription classDelegate];
664 }
665
666 @end
667
668 @implementation NSObject (EOInitialization)
669
670 - initWithEditingContext: (EOEditingContext *)ec
671 classDescription: (EOClassDescription *)classDesc
672 globalID: (EOGlobalID *)globalID;
673 {
674 return [self init];
675 }
676
677 @end
678
679
680 @implementation NSObject (EOClassDescriptionPrimitives)
681
682 // when you enable the NSDebugMLLogs here you will have a loop. dave
683 - (EOClassDescription *)classDescription
684 {
685 EOClassDescription *cd;
686
687 EOFLOGObjectFnStart();
688 //NSDebugMLLog(@"gsdb", @"self (%p)=%@ class=%@", self, self, [self class]);
689
690 cd = (EOClassDescription *)[EOClassDescription classDescriptionForClass:
691 [self class]];
692 //NSDebugMLLog(@"gsdb", @"classDescription=%@", cd);
693
694 EOFLOGObjectFnStop();
695
696 return cd;
697 }
698
699 - (NSString *)entityName
700 {
701 NSString *entityName;
702
703 EOFLOGObjectFnStart();
704
705 entityName = [[self classDescription] entityName];
706
707 EOFLOGObjectFnStop();
708
709 return entityName;
710 }
711
712 - (NSArray *)attributeKeys
713 {
714 NSArray *attributeKeys;
715
716 EOFLOGObjectFnStart();
717
718 attributeKeys = [[self classDescription] attributeKeys];
719
720 EOFLOGObjectFnStop();
721
722 return attributeKeys;
723 }
724
725 - (NSArray *)toOneRelationshipKeys
726 {
727 NSArray *toOneRelationshipKeys;
728
729 EOFLOGObjectFnStart();
730
731 toOneRelationshipKeys = [[self classDescription] toOneRelationshipKeys];
732
733 EOFLOGObjectFnStop();
734
735 return toOneRelationshipKeys;
736 }
737
738 - (NSArray *)toManyRelationshipKeys
739 {
740 NSArray *toManyRelationshipKeys;
741
742 EOFLOGObjectFnStart();
743
744 toManyRelationshipKeys = [[self classDescription] toManyRelationshipKeys];
745
746 EOFLOGObjectFnStop();
747
748 return toManyRelationshipKeys;
749 }
750
751 - (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey
752 {
753 NSString *inverse;
754
755 EOFLOGObjectFnStart();
756
757 inverse = [[self classDescription]
758 inverseForRelationshipKey: relationshipKey];
759
760 EOFLOGObjectFnStop();
761
762 return inverse;
763 }
764
765 - (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey
766 {
767 EODeleteRule rule;
768 EOClassDescription *cd;
769
770 EOFLOGObjectFnStart();
771 NSDebugMLLog(@"gsdb", @"self %p=%@", self, self);
772
773 cd = [self classDescription];
774 NSDebugMLLog(@"gsdb", @"cd %p=%@", cd, cd);
775
776 rule = [cd deleteRuleForRelationshipKey: relationshipKey];
777
778 EOFLOGObjectFnStop();
779
780 return rule;
781 }
782
783 - (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey
784 {
785 BOOL owns;
786
787 EOFLOGObjectFnStart();
788
789 owns = [[self classDescription]
790 ownsDestinationObjectsForRelationshipKey: relationshipKey];
791
792 EOFLOGObjectFnStop();
793
794 return owns;
795 }
796
797 - (EOClassDescription *)classDescriptionForDestinationKey:(NSString *)detailKey
798 {
799 EOClassDescription *cd;
800
801 EOFLOGObjectFnStart();
802 NSDebugMLLog(@"gsdb", @"detailKey=%@", detailKey);
803
804 cd = [[self classDescription] classDescriptionForDestinationKey: detailKey];
805
806 EOFLOGObjectFnStop();
807
808 return cd;
809 }
810
811 - (NSString *)userPresentableDescription
812 {
813 NSString *userPresentableDescription = nil;
814 NSArray *attrArray;
815 NSEnumerator *attrEnum;
816 NSString *key;
817
818 EOFLOGObjectFnStart();
819
820 attrArray = [self attributeKeys];
821 attrEnum = [attrArray objectEnumerator];
822
823 while ((key = [attrEnum nextObject]))
824 {
825 if ([key isEqualToString: @"name"])
826 return key;
827 }
828
829 attrEnum = [attrArray objectEnumerator];
830 while ((key = [attrEnum nextObject]))
831 {
832 if ([key isEqualToString: @"name"])
833 return key;
834 }
835
836 userPresentableDescription = [[self classDescription]
837 userPresentableDescription];
838
839 EOFLOGObjectFnStop();
840
841 return userPresentableDescription;
842 }
843
844 - (NSException *)validateValue: (id *)valueP
845 forKey: (NSString *)key
846 {
847 NSException *exception;
848 EOClassDescription *selfClassDescription;
849
850 EOFLOGObjectFnStart();
851
852 NSAssert(valueP, @"No value pointer");
853 NSDebugMLog(@"self (%p) [of class %@]=%@", self, [self class], self);
854
855 selfClassDescription = [self classDescription];
856 NSDebugMLog(@"selfClassDescription=%@",selfClassDescription);
857
858 exception = [selfClassDescription validateValue: valueP
859 forKey: key];
860 if (exception)
861 {
862 exception = [NSException exceptionWithName: [exception name]
863 reason: [exception reason]
864 userInfo: [NSDictionary
865 dictionaryWithObjectsAndKeys:
866 self, @"EOValidatedObjectUserInfoKey",
867 key, @"EOValidatedPropertyUserInfoKey",
868 nil, nil]];
869 }
870
871 if (exception == nil)
872 {
873 NSMutableString *selString = [NSMutableString stringWithCapacity: 32];
874 SEL validateSelector;
875 const char *str;
876 char l;
877
878 str = [key cString];
879 l = str[0];
880
881 if (islower(l))
882 l = toupper(l);
883
884 [selString appendString: @"validate"];
885 [selString appendString: [NSString stringWithCString: &l length: 1]];
886 [selString appendString: [NSString stringWithCString: &str[1]]];
887 [selString appendString: @":"];
888
889 validateSelector = NSSelectorFromString(selString);
890
891 if (validateSelector && [self respondsToSelector: validateSelector])
892 exception = [self performSelector: validateSelector
893 withObject: *valueP];
894 }
895
896 EOFLOGObjectFnStop();
897
898 return exception;
899 }
900
901 - (NSException *)validateForSave
902 {
903 NSMutableArray *expArray = nil;
904 NSException* exception;
905 int which;
906
907 EOFLOGObjectFnStart();
908
909 exception = [[self classDescription] validateObjectForSave: self];
910
911 if (exception)
912 {
913 if (!expArray)
914 expArray = [NSMutableArray array];
915 [expArray addObject:exception];
916 }
917
918 for (which = 0; which < 3; which++)
919 {
920 NSArray *keys;
921
922 if (which == 0)
923 keys = [self attributeKeys];
924 else if (which == 1)
925 keys = [self toOneRelationshipKeys];
926 else
927 keys = [self toManyRelationshipKeys];
928
929 if (keys)
930 {
931 int keysCount = [keys count];
932 int i;
933
934 for (i = 0; i < keysCount; i++)
935 {
936 NSString *key = [keys objectAtIndex: i];
937 id value = [self valueForKey: key];
938 id newValue = value;
939
940 exception = [self validateValue: &newValue
941 forKey: key];
942 if (exception)
943 {
944 if (!expArray)
945 expArray = [NSMutableArray array];
946 [expArray addObject: exception];
947 }
948
949 if ([newValue isEqual: value] == NO)
950 [self takeValue: newValue
951 forKey: key];
952 }
953 }
954 }
955
956 EOFLOGObjectFnStop();
957
958 return [NSException aggregateExceptionWithExceptions: expArray];
959 }
960
961 - (NSException *)validateForDelete
962 {
963 NSException *exception;
964
965 EOFLOGObjectFnStart();
966
967 exception = [[self classDescription] validateObjectForDelete: self];
968
969 EOFLOGObjectFnStop();
970
971 return exception;
972 }
973
974 - (void)awakeFromInsertionInEditingContext: (EOEditingContext *)editingContext
975 {
976 EOFLOGObjectFnStart();
977
978 [[self classDescription] awakeObject: self
979 fromInsertionInEditingContext: editingContext];
980
981 EOFLOGObjectFnStop();
982 }
983
984 - (void)awakeFromFetchInEditingContext: (EOEditingContext *)editingContext
985 {
986 EOFLOGObjectFnStart();
987
988 [[self classDescription] awakeObject: self
989 fromFetchInEditingContext: editingContext];
990
991 EOFLOGObjectFnStop();
992 }
993
994 @end
995
996
997 @implementation NSArray (EOShallowCopy)
998
999 - (NSArray *)shallowCopy
1000 {
1001 return [[NSArray alloc] initWithArray: self];
1002 }
1003
1004 @end
1005
1006
1007 @implementation NSObject (EOClassDescriptionExtras)
1008
1009 - (NSDictionary *)snapshot
1010 {
1011 //OK Can be Improved may be by using a dictionaryinitializer
1012 NSMutableDictionary *snapshot;
1013 NSArray *attributeKeys;
1014 NSArray *toOneRelationshipKeys;
1015 NSArray *toManyRelationshipKeys;
1016
1017 int attributeKeyCount;
1018 int toOneRelationshipKeyCount;
1019 int toManyRelationshipKeyCount;
1020 EONull *null = (EONull *)[EONull null];
1021 int i;
1022
1023 EOFLOGObjectFnStart();
1024 NSDebugMLLog(@"gsdb", @"self=%@", self);
1025
1026 attributeKeys = [self attributeKeys];
1027 NSDebugMLLog(@"gsdb", @"attributeKeys=%@", attributeKeys);
1028
1029 toOneRelationshipKeys = [self toOneRelationshipKeys];
1030 toManyRelationshipKeys = [self toManyRelationshipKeys];
1031
1032 attributeKeyCount = [attributeKeys count];
1033 toOneRelationshipKeyCount = [toOneRelationshipKeys count];
1034 toManyRelationshipKeyCount = [toManyRelationshipKeys count];
1035
1036 NSDebugMLLog(@"gsdb", @"attributeKeyCount=%d toOneRelationshipKeyCount=%d toManyRelationshipKeyCount=%d",
1037 attributeKeyCount, toOneRelationshipKeyCount,
1038 toManyRelationshipKeyCount);
1039
1040 snapshot = [NSMutableDictionary dictionaryWithCapacity: attributeKeyCount
1041 + toOneRelationshipKeyCount
1042 + toManyRelationshipKeyCount];
1043 NSDebugMLLog(@"gsdb", @"attributeKeys=%@", attributeKeys);
1044
1045 for (i = 0; i < attributeKeyCount; i++)
1046 {
1047 id key = [attributeKeys objectAtIndex: i];
1048 id value = [self storedValueForKey: key];
1049
1050 if (!value)
1051 value = null;
1052
1053 NSDebugMLLog(@"gsdb", @"snap=%p key=%@ ==> value %p=%@",
1054 snapshot, key, value, value);
1055 [snapshot setObject: value
1056 forKey: key];
1057 }
1058
1059 NSDebugMLLog(@"gsdb", @"toOneRelationshipKeys=%@", toOneRelationshipKeys);
1060
1061 for (i = 0; i < toOneRelationshipKeyCount; i++)
1062 {
1063 id key = [toOneRelationshipKeys objectAtIndex: i];
1064 id value = [self storedValueForKey: key];
1065
1066 if (!value)
1067 value = null;
1068
1069 NSDebugMLLog(@"gsdb", @"TOONE snap=%p key=%@ ==> value %p=%@",
1070 snapshot, key, value, value);
1071
1072 [snapshot setObject: value
1073 forKey: key];
1074 }
1075
1076 NSDebugMLLog(@"gsdb", @"toManyRelationshipKeys=%@", toManyRelationshipKeys);
1077
1078 for (i = 0; i < toManyRelationshipKeyCount; i++)
1079 {
1080 id key = [toManyRelationshipKeys objectAtIndex: i];
1081 id value = [self storedValueForKey: key];
1082
1083 if (value)
1084 {
1085 NSDebugMLLog(@"gsdb", @"TOMANY snap=%p key=%@ ==> value %p=%@",
1086 snapshot, key, value, value);
1087
1088 value = AUTORELEASE([value shallowCopy]);
1089 NSDebugMLLog(@"gsdb", @"TOMANY snap=%p key=%@ ==> value %p=%@",
1090 snapshot, key, value, value);
1091
1092 [snapshot setObject: value
1093 forKey: key];
1094 }
1095 /* //TODO-VERIFY or set it to eonull ?
1096 else
1097 value=null;
1098 */
1099 }
1100
1101 NSDebugMLLog(@"gsdb", @"self=%p snapshot=%p", self, snapshot);
1102 NSDebugMLLog(@"gsdb", @"self %p=%@\nsnapshot %p=%@", self, self, snapshot,
1103 snapshot);
1104
1105 EOFLOGObjectFnStop();
1106
1107 NSDebugMLLog(@"gsdb", @"self=%p snapshot=%p count=%d",
1108 self, snapshot, [snapshot count]);
1109
1110 return snapshot;
1111 }
1112
1113 - (void)updateFromSnapshot: (NSDictionary *)snapshot
1114 {
1115 NSEnumerator *snapshotEnum = [snapshot keyEnumerator];
1116 NSString *key;
1117 EONull *null = (EONull *)[EONull null];
1118 id val;
1119
1120 while ((key = [snapshotEnum nextObject]))
1121 {
1122 val = [snapshot objectForKey: key];
1123
1124 if ([val isEqual: null])
1125 val = nil;
1126
1127 if ([val isKindOfClass: [NSArray class]])
1128 val = AUTORELEASE([AUTORELEASE([val shallowCopy]) mutableCopy]);
1129
1130 [self takeStoredValue: val forKey: key];
1131 }
1132 }
1133
1134 - (BOOL)isToManyKey: (NSString *)key
1135 {
1136 NSArray *toMany = [self toManyRelationshipKeys];
1137 NSEnumerator *toManyEnum = [toMany objectEnumerator];
1138 NSString *relationship;
1139
1140 while ((relationship = [toManyEnum nextObject]))
1141 {
1142 if ([relationship isEqualToString: key])
1143 return YES;
1144 }
1145
1146 return NO;
1147 }
1148
1149 - (NSException *)validateForInsert
1150 {
1151 NSException *exception;
1152
1153 EOFLOGObjectFnStart();
1154
1155 exception = [self validateForSave];
1156
1157 EOFLOGObjectFnStop();
1158
1159 return exception;
1160 }
1161
1162 - (NSException *)validateForUpdate
1163 {
1164 NSException *exception;
1165
1166 EOFLOGObjectFnStart();
1167
1168 exception = [self validateForSave];
1169
1170 EOFLOGObjectFnStop();
1171
1172 return exception;
1173 }
1174
1175 - (NSArray *)allPropertyKeys
1176 {
1177 NSArray *toOne;
1178 NSArray *toMany;
1179 NSArray *attr;
1180 NSMutableArray *ret;
1181
1182 attr = [self attributeKeys];
1183 toOne = [self toOneRelationshipKeys];
1184 toMany = [self toManyRelationshipKeys];
1185
1186 ret = [NSMutableArray arrayWithCapacity:
1187 [attr count] +
1188 [toOne count] + [toMany count]];
1189
1190 [ret addObjectsFromArray: attr];
1191 [ret addObjectsFromArray: toOne];
1192 [ret addObjectsFromArray: toMany];
1193
1194 return ret;
1195 }
1196
1197 - (void)clearProperties
1198 {
1199 NSArray *toOne = nil;
1200 NSArray *toMany = nil;
1201 NSEnumerator *relEnum = nil;
1202 NSString *key = nil;
1203 EOFLOGObjectFnStart();
1204 toOne = [self toOneRelationshipKeys];
1205 toMany = [self toManyRelationshipKeys];
1206
1207 relEnum = [toOne objectEnumerator];
1208 while ((key = [relEnum nextObject]))
1209 [self takeStoredValue: nil forKey: key];
1210
1211 relEnum = [toMany objectEnumerator];
1212 while ((key = [relEnum nextObject]))
1213 [self takeStoredValue: nil forKey: key];
1214 EOFLOGObjectFnStop();
1215 }
1216
1217 - (void)propagateDeleteWithEditingContext: (EOEditingContext *)editingContext
1218 {
1219 EOFLOGObjectFnStart();
1220
1221 [[self classDescription] propagateDeleteForObject: self
1222 editingContext: editingContext];
1223
1224 EOFLOGObjectFnStop();
1225 }
1226
1227 - (NSString *)eoShallowDescription
1228 {
1229 [self notImplemented: _cmd];
1230 return nil; //TODO
1231 }
1232
1233 - (NSString *)eoDescription
1234 {
1235 NSArray *attrArray = [self allPropertyKeys];
1236 NSEnumerator *attrEnum = [attrArray objectEnumerator];
1237 NSString *key;
1238 NSMutableString *ret = [NSMutableString
1239 stringWithCapacity: 5 * [attrArray count]];
1240
1241 [ret appendString: [NSString stringWithFormat:@"<%@ (%p)",
1242 NSStringFromClass([self class]), self]];
1243
1244 while ((key = [attrEnum nextObject]))
1245 {
1246 [ret appendString: [NSString stringWithFormat: @" %@=%@",
1247 key, [self valueForKey: key]]];
1248 }
1249
1250 [ret appendString: [NSString stringWithFormat: @">"]];
1251
1252 return ret; //TODO
1253 }
1254
1255 @end
1256
1257
1258 @implementation NSObject (EOKeyRelationshipManipulation)
1259
1260 - (void)addObject: object
1261 toPropertyWithKey: (NSString *)key
1262 {
1263 const char *str = NULL;
1264
1265 EOFLOGObjectFnStart();
1266 NSDebugMLLog(@"gsdb", @"self=%@", self);
1267 NSDebugMLLog(@"gsdb", @"object=%@", object);
1268 NSDebugMLLog(@"gsdb", @"key=%@", key);
1269
1270 str = [key cString];
1271
1272 NSDebugMLLog(@"gsdb", @"*+* ciao3 %@", key);
1273 NSDebugMLLog(@"gsdb", @"*+* ciao3 %@", object);
1274
1275 if ([key length])
1276 {
1277 NSMutableString *selString = [NSMutableString stringWithCapacity: 25];
1278 SEL addToSelector;
1279 char l = str[0];
1280
1281 if (islower(l))
1282 l = toupper(l);
1283
1284 [selString appendString: @"addTo"];
1285 [selString appendString: [NSString stringWithCString: &l length: 1]];
1286 [selString appendString: [NSString stringWithCString: &str[1]]];
1287 [selString appendString: @":"];
1288
1289 addToSelector = NSSelectorFromString(selString);
1290
1291 if (addToSelector && [self respondsToSelector: addToSelector] == YES)
1292 {
1293 NSDebugMLLog(@"gsdb", @"selector=%@", selString);
1294
1295 [self performSelector: addToSelector
1296 withObject: object];
1297 }
1298 else
1299 {
1300 id val = nil;
1301
1302 if ([self isToManyKey: key] == YES)
1303 {
1304 EOFLOGObjectLevel(@"gsdb", @"to many");
1305
1306 val = [self valueForKey: key]; //should use storedValueForKey: ?
1307
1308 NSDebugMLLog(@"gsdb", @"to many val=%@ (%@)", val, [val class]);
1309
1310 if ([val containsObject: object])
1311 {
1312 NSDebugMLog(@"Object %p already in too many val=%@ (%@)",
1313 object, val, [val class]);
1314 }
1315 else
1316 {
1317 if ([val isKindOfClass: [NSMutableArray class]])
1318 {
1319 EOFLOGObjectLevel(@"gsdb", @"to many2");
1320 [self willChange];
1321 [val addObject: object];
1322 }
1323 else
1324 {
1325 NSMutableArray *relArray;
1326
1327 if (val)
1328 relArray = AUTORELEASE([val mutableCopy]);
1329 else
1330 relArray = [NSMutableArray arrayWithCapacity: 10];
1331
1332 NSDebugMLLog(@"gsdb", @"relArray=%@ (%@)",
1333 relArray, [relArray class]);
1334
1335 [relArray addObject: object];
1336 NSDebugMLLog(@"gsdb", @"relArray=%@ (%@)",
1337 relArray, [relArray class]);
1338
1339 [self takeValue: relArray
1340 forKey: key];
1341 }
1342 }
1343 }
1344 else
1345 {
1346 EOFLOGObjectLevel(@"gsdb", @"key is not to many");
1347
1348 [self takeValue: object
1349 forKey: key];
1350 }
1351 }
1352 }
1353
1354 NSDebugMLLog(@"gsdb", @"self=%@", self);
1355 NSDebugMLLog(@"gsdb", @"object=%@", object);
1356
1357 EOFLOGObjectFnStop();
1358 }
1359
1360 - (void)removeObject: object
1361 fromPropertyWithKey: (NSString *)key
1362 {
1363 //self valueForKey:
1364 const char *str = NULL;
1365
1366 EOFLOGObjectFnStart();
1367 NSDebugMLLog(@"gsdb", @"self=%@", self);
1368 NSDebugMLLog(@"gsdb", @"object=%@", object);
1369 NSDebugMLLog(@"gsdb", @"key=%@ class=%@", key, [key class]);
1370
1371 str = [key cString];
1372
1373 if ([key length])
1374 {
1375 NSMutableString *selString = [NSMutableString stringWithCapacity: 25];
1376 SEL removeFromSelector;
1377 char l = str[0];
1378
1379 if (islower(l))
1380 l = toupper(l);
1381
1382 [selString appendString: @"removeFrom"];
1383 NSDebugMLLog(@"gsdb", @"selString=%@", selString);
1384 [selString appendString: [NSString stringWithCString: &l
1385 length: 1]];
1386 NSDebugMLLog(@"gsdb", @"selString=%@", selString);
1387 [selString appendString: [NSString stringWithCString: &str[1]]];
1388 NSDebugMLLog(@"gsdb", @"selString=%@", selString);
1389 [selString appendString: @":"];
1390 NSDebugMLLog(@"gsdb", @"selString=%@", selString);
1391
1392 removeFromSelector = NSSelectorFromString(selString);
1393
1394 NSDebugMLLog(@"gsdb", @"selString=%@ removeFromSelector=%p", selString,
1395 (void*)removeFromSelector);
1396
1397 if (removeFromSelector && [self respondsToSelector: removeFromSelector])
1398 {
1399 EOFLOGObjectLevel(@"gsdb", @"responds=YES");
1400 [self performSelector: removeFromSelector
1401 withObject: object];
1402 }
1403 else
1404 {
1405 id val = nil;
1406
1407 EOFLOGObjectLevel(@"gsdb", @"responds=NO");
1408
1409 if ([self isToManyKey:key] == YES)
1410 {
1411 EOFLOGObjectLevel(@"gsdb", @"key is to many");
1412
1413 val = [self valueForKey: key];
1414 NSDebugMLLog(@"gsdb", @"val=%@", val);
1415
1416 if ([val isKindOfClass: [NSMutableArray class]])
1417 {
1418 [self willChange];
1419 [val removeObject: object];
1420 }
1421 else
1422 {
1423 NSMutableArray *relArray = nil;
1424
1425 if (val)
1426 {
1427 relArray = AUTORELEASE([val mutableCopy]);
1428
1429 [relArray removeObject: object];
1430 [self takeValue: relArray
1431 forKey: key];
1432 }
1433 }
1434 }
1435 else
1436 {
1437 EOFLOGObjectLevel(@"gsdb", @"key is not to many");
1438 [self takeValue: nil
1439 forKey: key];
1440 }
1441 }
1442 }
1443
1444 NSDebugMLLog(@"gsdb", @"self=%@", self);
1445 NSDebugMLLog(@"gsdb", @"object=%@", object);
1446
1447 EOFLOGObjectFnStop();
1448 }
1449
1450 -(void)_setObject: (id)object
1451 forBothSidesOfRelationshipWithKey: (NSString*)key
1452 {
1453 //Near OK
1454 NSString *inverseKey;
1455 id oldObject;
1456
1457 EOFLOGObjectFnStart();
1458 NSDebugMLLog(@"gsdb", @"self=%@", self);
1459 NSDebugMLLog(@"gsdb", @"object=%@", object);
1460 NSDebugMLLog(@"gsdb", @"key=%@", key);
1461
1462 inverseKey = [self inverseForRelationshipKey:key];
1463 NSDebugMLLog(@"gsdb", @"inverseKey=%@", inverseKey);
1464
1465 oldObject = [self valueForKey: key];
1466 NSDebugMLLog(@"gsdb", @"oldObject=%@", oldObject);
1467
1468 if (inverseKey)
1469 {
1470 [oldObject removeObject: self
1471 fromPropertyWithKey: inverseKey];
1472 [object addObject: self
1473 toPropertyWithKey: inverseKey];
1474 /* if ([object isToManyKey:inverseKey])
1475 {
1476 //??
1477 EOFLOGObjectLevel(@"gsdb",@"Inverse is to many");
1478 [oldObject removeObject:self
1479 fromPropertyWithKey:inverseKey];
1480 [object addObject:self
1481 toPropertyWithKey:inverseKey];
1482 }
1483 else
1484 {
1485 EOFLOGObjectLevel(@"gsdb",@"Inverse is not to many");
1486 //OK
1487 //MIRKO if ((inverseKey = [oldObject inverseForRelationshipKey:key]))
1488 //MIRKO [oldObject removeObject:self
1489 // fromPropertyWithKey:inverseKey];
1490 [oldObject takeValue:nil
1491 forKey:inverseKey];
1492 [object takeValue:self
1493 forKey:inverseKey];
1494 };
1495 */
1496 }
1497
1498 [self takeValue: object
1499 forKey: key];
1500
1501 NSDebugMLLog(@"gsdb", @"self=%@", self);
1502 NSDebugMLLog(@"gsdb", @"object=%@", object);
1503
1504 EOFLOGObjectFnStop();
1505 }
1506
1507 - (void)addObject: (id)object
1508 toBothSidesOfRelationshipWithKey: (NSString *)key
1509 {
1510 EOFLOGObjectFnStart();
1511
1512 NSDebugMLLog(@"gsdb", @"self=%@", self);
1513 NSDebugMLLog(@"gsdb", @"object=%@", object);
1514 NSDebugMLLog(@"gsdb", @"key=%@", key);
1515
1516 // 2 differents cases: to-one and to-many relation
1517 if ([self isToManyKey:key]) // to-many
1518 {
1519 //See if there's an inverse relationship
1520 NSString *inverseKey = [self inverseForRelationshipKey: key];
1521
1522 NSDebugMLLog(@"gsdb", @"self %p=%@,object %p=%@ key=%@ inverseKey=%@",
1523 self,
1524 self,
1525 object,
1526 object,
1527 key,
1528 inverseKey);
1529
1530 // First add object to self relation array
1531 [self addObject: object
1532 toPropertyWithKey: key];
1533
1534 if (inverseKey) //if no inverse relation do nothing
1535 {
1536 // See if inverse relationship is to-many or to-one
1537 if ([object isToManyKey: inverseKey])
1538 {
1539 //TODO VERIFY
1540 [object addObject:self
1541 toPropertyWithKey:inverseKey];
1542 }
1543 else
1544 {
1545 // Previous value, if any
1546 id oldObject = [object valueForKey: inverseKey];
1547
1548 NSDebugMLLog(@"gsdb", @"oldObject=%@", oldObject);
1549
1550 if (oldObject)
1551 {
1552 //TODO VERIFY
1553 [object removeObject:oldObject
1554 fromPropertyWithKey:inverseKey];
1555 }
1556
1557 // Just set self into object relationship property
1558 [object takeValue: self
1559 forKey: inverseKey];
1560 }
1561 }
1562 }
1563 else
1564 {
1565 [self _setObject: object
1566 forBothSidesOfRelationshipWithKey: key];
1567 }
1568
1569 NSDebugMLLog(@"gsdb", @"self=%@", self);
1570 NSDebugMLLog(@"gsdb", @"object=%@", object);
1571
1572 EOFLOGObjectFnStop();
1573 }
1574
1575 - (void)removeObject: (id)object
1576 fromBothSidesOfRelationshipWithKey: (NSString *)key
1577 {
1578 NSString *inverseKey;
1579
1580 [self removeObject: object
1581 fromPropertyWithKey: key];
1582
1583 if ((inverseKey = [self inverseForRelationshipKey: key]))
1584 [object removeObject: self
1585 fromPropertyWithKey: inverseKey];
1586 }
1587
1588 @end
1589
1590
1591 @implementation NSException (EOValidationError)
1592
1593 + (NSException *)validationExceptionWithFormat: (NSString *)format, ...
1594 {
1595 NSException *exp = nil;
1596 NSString *aName = nil;
1597 va_list args;
1598
1599 va_start(args, format);
1600
1601 aName = AUTORELEASE([[NSString alloc] initWithFormat: format
1602 arguments: args]);
1603 exp = [NSException exceptionWithName: EOValidationException
1604 reason: aName
1605 userInfo: nil];
1606
1607 va_end(args);
1608
1609 return exp;
1610 }
1611
1612 + (NSException *)aggregateExceptionWithExceptions: (NSArray *)subexceptions
1613 {
1614 NSException *exp = nil;
1615
1616 if ([subexceptions count] == 1)
1617 exp = [subexceptions objectAtIndex: 0];
1618 else if ([subexceptions count] > 1)
1619 {
1620 NSString *aName = nil, *aReason = nil;
1621 NSMutableDictionary *aUserInfo = nil;
1622
1623 exp = [subexceptions objectAtIndex: 0];
1624
1625 aName = [exp name];
1626 aReason = [exp reason];
1627 aUserInfo = AUTORELEASE([[exp userInfo] mutableCopy]);
1628
1629 [aUserInfo setObject: subexceptions
1630 forKey: EOAdditionalExceptionsKey];
1631
1632 exp = [NSException exceptionWithName: aName
1633 reason: aReason
1634 userInfo: aUserInfo];
1635 }
1636
1637 return exp;
1638 }
1639
1640 - (NSException *)exceptionAddingEntriesToUserInfo: (NSDictionary *)additions
1641 {
1642 NSException *exp = nil;
1643 NSString *aName = nil, *aReason = nil;
1644 NSMutableDictionary *aUserInfo = nil;
1645
1646 aName = [self name];
1647 aReason = [self reason];
1648 aUserInfo = AUTORELEASE([[self userInfo] mutableCopy]);
1649
1650 [aUserInfo setObject: [additions allValues]
1651 forKey: EOValidatedObjectUserInfoKey];
1652 [aUserInfo setObject: [additions allKeys]
1653 forKey: EOValidatedPropertyUserInfoKey];
1654
1655 exp = [NSException exceptionWithName: aName
1656 reason: aReason
1657 userInfo: aUserInfo];
1658
1659 return exp;
1660 }
1661
1662 @end
1663
1664
1665 @implementation NSObject (EOClassDescriptionClassDelegate)
1666
1667 - (BOOL)shouldPropagateDeleteForObject: (id)object
1668 inEditingContext: (EOEditingContext *)ec
1669 forRelationshipKey: (NSString *)key
1670 {
1671 return YES;
1672 }
1673
1674 @end
1675
1676
1677 @implementation NSObject (_EOValueMerging)
1678
1679 - (void)mergeValue: (id)value
1680 forKey: (id)key
1681 {
1682 [self notImplemented:_cmd];
1683 return;
1684 }
1685
1686 - (void)mergeChangesFromDictionary: (NSDictionary *)changes
1687 {
1688 [self notImplemented:_cmd];
1689 return;
1690 }
1691
1692 - (NSDictionary *)changesFromSnapshot: (NSDictionary *)snapshot
1693 {
1694 id propertiesList[2];
1695 NSArray *properties;
1696 int h, i, count;
1697 NSMutableArray *newKeys = [NSMutableArray arrayWithCapacity: 16];
1698 NSMutableArray *newVals = [NSMutableArray arrayWithCapacity: 16];
1699 NSString *key;
1700
1701 propertiesList[0] = [self attributeKeys];
1702 propertiesList[1] = [self toOneRelationshipKeys];
1703
1704 for (h = 0; h < 2; h++)
1705 {
1706 id val, oldVal;
1707
1708 properties = propertiesList[h];
1709 count = [properties count];
1710
1711 for(i = 0; i < count; i++)
1712 {
1713 key = [properties objectAtIndex: i];
1714 val = [self storedValueForKey: key];
1715 oldVal = [snapshot storedValueForKey: key];
1716
1717 if (val == oldVal || [val isEqual: oldVal] == YES)
1718 continue;
1719
1720 [newKeys addObject: key];
1721 [newVals addObject: val];
1722 }
1723 }
1724
1725 properties = [self toManyRelationshipKeys];
1726 count = [properties count];
1727
1728 for(i = 0; i < count; i++)
1729 {
1730 NSMutableArray *array, *objects;
1731 NSArray *val, *oldVal;
1732 int valCount, oldValCount;
1733
1734 key = [properties objectAtIndex: i];
1735 val = [self storedValueForKey: key];
1736 oldVal = [snapshot objectForKey: key];
1737
1738 if ((id)val == [EONull null])
1739 val = nil;
1740
1741 if ((id)oldVal == [EONull null])
1742 oldVal = nil;
1743
1744 if (!val && !oldVal)
1745 continue;
1746
1747 valCount = [val count];
1748 oldValCount = [oldVal count];
1749
1750 if (valCount == 0 && oldValCount == 0)
1751 continue;
1752
1753 array = [NSMutableArray arrayWithCapacity: 2];
1754 if (val && valCount>0)
1755 {
1756 objects = [NSMutableArray arrayWithArray: val];
1757 [objects removeObjectsInArray: oldVal];
1758 }
1759 else
1760 objects = [NSMutableArray arrayWithCapacity: 1];
1761
1762 [array addObject: objects];
1763
1764 if (val && valCount > 0)
1765 {
1766 objects = [NSMutableArray arrayWithArray: oldVal];
1767 [objects removeObjectsInArray: val];
1768 }
1769 else
1770 objects = [NSMutableArray arrayWithCapacity: 1];
1771
1772 [array addObject: objects];
1773
1774 [newKeys addObject: key];
1775 [newVals addObject: array];
1776 }
1777
1778 return [NSDictionary dictionaryWithObjects: newVals forKeys: newKeys];
1779 }
1780
1781 - (void)reapplyChangesFromSnapshot: (NSDictionary *)changes
1782 {
1783 [self notImplemented: _cmd];
1784 }
1785
1786 @end
1787
1788 @implementation NSObject (_EOEditingContext)
1789
1790 -(EOEditingContext*)editingContext
1791 {
1792 return [EOObserverCenter observerForObject: self
1793 ofClass: [EOEditingContext class]];
1794 }
1795
1796 @end
1797

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26