Key value coding and class description support added.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@8219 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2000-11-27 22:26:08 +00:00
parent 47d960b33b
commit fe09500665
8 changed files with 650 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2000-11-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSClassDescription.m: New MacOS-X class added.
* Headers/Foundation/NSClassDescription.m: New MacOS-X class added.
* Headers/Foundation/NSKeyvalueCoding.m: New MacOS-X protocol added.
* Source/NSObject.m: New MacOS-X key value coding methods added.
Only objects currently supported - needs work to support scalar
types too!
2000-11-23 Mirko Viviani <mirko.viviani@rccr.cremona.it>
* Source/NSBundle.m ([NSBundle +_addFrameworkFromClass:]): fixed an

View file

@ -38,6 +38,7 @@
#include <Foundation/NSBundle.h>
#include <Foundation/NSByteOrder.h>
#include <Foundation/NSCharacterSet.h>
#include <Foundation/NSClassDescription.h>
#include <Foundation/NSCoder.h>
#include <Foundation/NSConnection.h>
#include <Foundation/NSDate.h>
@ -57,6 +58,7 @@
#include <Foundation/NSGeometry.h>
#include <Foundation/NSHost.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSKeyValueCoding.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSMethodSignature.h>

View file

@ -0,0 +1,61 @@
/* Interface for NSClassDescription for GNUStep
Copyright (C) 2000 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Date: 2000
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#ifndef __NSClassDescription_h_GNUSTEP_BASE_INCLUDE
#define __NSClassDescription_h_GNUSTEP_BASE_INCLUDE
#include <Foundation/NSObject.h>
#include <Foundation/NSException.h>
@class NSArray;
@class NSDictionary;
@class NSString;
GS_EXPORT NSString* const NSClassDescriptionNeededForClassNotification;
@interface NSClassDescription : NSObject
+ (NSClassDescription*) classDescriptionForClass: (Class)aClass;
+ (void) invalidateClassDescriptionCache;
+ (void) registerClassDescription: (NSClassDescription*)aDescription
forClass: (Class)aClass;
- (NSArray*) attributeKeys;
- (NSString*) inverseForRelationshipKey: (NSString*)aKey;
- (NSArray*) toManyRelationshipKeys;
- (NSArray*) toOneRelationshipKeys;
@end
@interface NSObject (NSClassDescriptionPrimitives)
- (NSArray*) attributeKeys;
- (NSClassDescription*) classDescription;
- (NSString*) inverseForRelationshipKey: (NSString*)aKey;
- (NSArray*) toManyRelationshipKeys;
- (NSArray*) toOneRelationshipKeys;
@end
#endif

View file

@ -0,0 +1,55 @@
/* Interface for NSKeyvalueCoding for GNUStep
Copyright (C) 2000 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Date: 2000
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#ifndef __NSKeyValueCoding_h_GNUSTEP_BASE_INCLUDE
#define __NSKeyValueCoding_h_GNUSTEP_BASE_INCLUDE
#include <Foundation/NSObject.h>
@class NSArray;
@class NSDictionary;
@class NSString;
@interface NSObject (NSKeyValueCoding)
+ (BOOL) accessInstanceVariablesDirectly;
+ (BOOL) useStoredAccessor;
- (id) handleQueryWithUnboundKey: (NSString*)aKey;
- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey;
- (id) storedValueForKey: (NSString*)aKey;
- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey;
- (void) takeValue: (id)anObject forKey: (NSString*)aKey;
- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey;
- (void) takeValuesFromDictionary: (NSDictionary*)aDictionary;
- (void) unableToSetNilForKey: (NSString*)aKey;
- (id) valueForKey: (NSString*)aKey;
- (id) valueForKeyPath: (NSString*)aKey;
- (NSDictionary*) valuesForKeys: (NSArray*)keys;
@end
#endif

View file

@ -157,6 +157,7 @@ NSBundle.m \
NSCalendarDate.m \
NSCallBacks.m \
NSCharacterSet.m \
NSClassDescription.m \
NSCoder.m \
NSCopyObject.m \
NSConcreteValue.m \
@ -265,6 +266,7 @@ NSBitmapCharSet.h \
NSBundle.h \
NSByteOrder.h \
NSCharacterSet.h \
NSClassDescription.h \
NSCoder.h \
NSConcreteNumber.h \
NSConcreteValue.h \
@ -291,6 +293,7 @@ NSGSet.h \
NSHashTable.h \
NSHost.h \
NSInvocation.h \
NSKeyValueEncoding.h \
NSLock.h \
NSMapTable.h \
NSMethodSignature.h \

143
Source/NSClassDescription.m Normal file
View file

@ -0,0 +1,143 @@
/* NSClassDescription
Copyright (C) 2000 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Date: 2000
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include <Foundation/NSClassDescription.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSNotification.h>
@implementation NSClassDescription
static NSRecursiveLock *mapLock = nil;
static NSMapTable *classMap;
+ (NSClassDescription*) classDescriptionForClass: (Class)aClass
{
NSClassDescription *description;
[mapLock lock];
description = NSMapGet(classMap, aClass);
if (description == nil)
{
NSNotificationCenter *nc;
nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName: NSClassDescriptionNeededForClassNotification
object: aClass];
description = NSMapGet(classMap, aClass);
}
RETAIN(description);
[mapLock unlock];
return AUTORELEASE(description);
}
+ (void) initialize
{
if (self == [NSClassDescription class])
{
classMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 100);
mapLock = [NSRecursiveLock new];
}
}
+ (void) invalidateClassDescriptionCache
{
[mapLock lock];
NSResetMapTable(classMap);
[mapLock unlock];
}
+ (void) registerClassDescription: (NSClassDescription*)aDescription
forClass: (Class)aClass
{
if (aDescription != nil && aClass != 0)
{
[mapLock lock];
NSMapInsert(classMap, aClass, aDescription);
[mapLock unlock];
}
}
- (NSArray*) attributeKeys
{
return nil;
}
- (NSString*) inverseForRelationshipKey: (NSString*)aKey
{
return nil;
}
- (NSArray*) toManyRelationshipKeys
{
return nil;
}
- (NSArray*) toOneRelationshipKeys
{
return nil;
}
@end
@implementation NSObject(ClassDescriptionForwards)
static Class NSClassDescriptionClass = 0;
- (NSArray*) attributeKeys
{
return [[self classDescription] attributeKeys];
}
- (NSClassDescription*) classDescription
{
if (NSClassDescriptionClass == 0)
{
NSClassDescriptionClass = [NSClassDescription class];
}
return [NSClassDescriptionClass classDescriptionForClass: [self class]];
}
- (NSString*) inverseForRelationshipKey: (NSString*)aKey
{
return [[self classDescription] inverseForRelationshipKey: aKey];
}
- (NSArray*) toManyRelationshipKeys
{
return [[self classDescription] toManyRelationshipKeys];
}
- (NSArray*) toOneRelationshipKeys
{
return [[self classDescription] toOneRelationshipKeys];
}
@end

View file

@ -1276,6 +1276,376 @@ static BOOL deallocNotifications = NO;
@end
#include <Foundation/NSKeyValueCoding.h>
#include <Foundation/NSNull.h>
static BOOL
GSGetValue(id obj, NSString *iVarName, id *data)
{
const char *name = [iVarName cString];
Class class;
struct objc_ivar_list *ivars;
struct objc_ivar *ivar = 0;
int offset;
const char *type;
unsigned int size;
class = [obj class];
while (class != nil && ivar == 0)
{
ivars = class->ivars;
class = class->super_class;
if (ivars != 0)
{
int i;
for (i = 0; i < ivars->ivar_count; i++)
{
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
{
ivar = &ivars->ivar_list[i];
break;
}
}
}
}
if (ivar == 0)
{
return NO;
}
offset = ivar->ivar_offset;
type = ivar->ivar_type;
size = objc_sizeof_type(type);
memcpy(data, ((void*)obj) + offset, size);
return YES;
}
static BOOL
GSSetValue(id obj, NSString *iVarName, id *data)
{
const char *name = [iVarName cString];
Class class;
struct objc_ivar_list *ivars;
struct objc_ivar *ivar = 0;
int offset;
const char *type;
unsigned int size;
class = [obj class];
while (class != nil && ivar == 0)
{
ivars = class->ivars;
class = class->super_class;
if (ivars != 0)
{
int i;
for (i = 0; i < ivars->ivar_count; i++)
{
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
{
ivar = &ivars->ivar_list[i];
break;
}
}
}
}
if (ivar == 0)
{
return NO;
}
offset = ivar->ivar_offset;
type = ivar->ivar_type;
size = objc_sizeof_type(type);
memcpy(((void*)obj) + offset, data, size);
return YES;
}
@implementation NSObject (KeyValueCoding)
+ (BOOL) accessInstanceVariablesDirectly
{
return YES;
}
+ (BOOL) useStoredAccessor
{
return YES;
}
- (id) handleQueryWithUnboundKey: (NSString*)aKey
{
return nil;
}
- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey
{
[NSException raise: NSGenericException
format: @"Unable to find %@ in %@", aKey, anObject];
}
- (id) storedValueForKey: (NSString*)aKey
{
SEL sel;
if ([[self class] useStoredAccessor] == NO)
{
return [self valueForKey: aKey];
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_get%@",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_%@", aKey]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
id v;
if (GSGetValue(self, [NSString stringWithFormat: @"_%@", aKey],
(void*)&v) == YES)
{
return v;
}
if (GSGetValue(self, aKey, (void*)&v) == YES)
{
return v;
}
}
sel = NSSelectorFromString([NSString stringWithFormat: @"get%@",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
sel = NSSelectorFromString(aKey);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
[self handleTakeValue: nil forUnboundKey: aKey];
return nil;
}
- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey
{
SEL sel;
if ([[self class] useStoredAccessor] == NO)
{
[self takeValue: anObject forKey: aKey];
return;
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_set%@:",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
[self performSelector: sel withObject: anObject];
return;
}
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
if (GSSetValue(self, [NSString stringWithFormat: @"_%@", aKey],
(void*)&anObject) == YES)
{
return;
}
if (GSSetValue(self, aKey, (void*)&anObject) == YES)
{
return;
}
}
sel = NSSelectorFromString([NSString stringWithFormat: @"set%@:",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
[self performSelector: sel withObject: anObject];
return;
}
[self handleTakeValue: anObject forUnboundKey: aKey];
}
- (void) takeValue: (id)anObject forKey: (NSString*)aKey
{
SEL sel;
sel = NSSelectorFromString([NSString stringWithFormat: @"set%@:",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
[self performSelector: sel withObject: anObject];
return;
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_set%@:",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
[self performSelector: sel withObject: anObject];
return;
}
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
if (GSSetValue(self, [NSString stringWithFormat: @"_%@", aKey],
(void*)&anObject) == YES)
{
return;
}
if (GSSetValue(self, aKey, (void*)&anObject) == YES)
{
return;
}
}
[self handleTakeValue: anObject forUnboundKey: aKey];
}
- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey
{
NSArray *keys = [aKey componentsSeparatedByString: @"."];
id obj = self;
unsigned count = [keys count];
unsigned pos;
for (pos = 0; pos + 1 < count; pos++)
{
obj = [obj valueForKey: [keys objectAtIndex: pos]];
}
if (pos < count)
{
[obj takeValue: anObject forKey: [keys objectAtIndex: pos]];
}
}
- (void) takeValuesFromDictionary: (NSDictionary*)aDictionary
{
NSEnumerator *enumerator = [aDictionary keyEnumerator];
NSNull *null = [NSNull null];
NSString *key;
while ((key = [enumerator nextObject]) != nil)
{
id obj = [aDictionary objectForKey: key];
if (obj == null)
{
obj = nil;
}
[self takeValue: obj forKey: key];
}
}
- (void) unableToSetNilForKey: (NSString*)aKey
{
[NSException raise: NSInvalidArgumentException
format: @"Given nil value to set for key"];
}
- (id) valueForKey: (NSString*)aKey
{
SEL sel;
sel = NSSelectorFromString([NSString stringWithFormat: @"get%@",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
sel = NSSelectorFromString(aKey);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_get%@",
[aKey capitalizedString]]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
sel = NSSelectorFromString([NSString stringWithFormat: @"_%@", aKey]);
if ([self respondsToSelector: sel] == YES)
{
return [self performSelector: sel];
}
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
id v;
if (GSGetValue(self, [NSString stringWithFormat: @"_%@", aKey],
(void*)&v) == YES)
{
return v;
}
if (GSGetValue(self, aKey, (void*)&v) == YES)
{
return v;
}
}
[self handleTakeValue: nil forUnboundKey: aKey];
return nil;
}
- (id) valueForKeyPath: (NSString*)aKey
{
NSArray *keys = [aKey componentsSeparatedByString: @"."];
id obj = self;
unsigned count = [keys count];
unsigned pos;
for (pos = 0; pos < count; pos++)
{
obj = [obj valueForKey: [keys objectAtIndex: pos]];
}
return obj;
}
- (NSDictionary*) valuesForKeys: (NSArray*)keys
{
NSMutableDictionary *dict;
NSNull *null = [NSNull null];
unsigned count = [keys count];
unsigned pos;
dict = [NSMutableDictionary dictionaryWithCapacity: count];
for (pos = 0; pos < count; pos++)
{
NSString *key = [keys objectAtIndex: pos];
id val = [self valueForKey: key];
if (val == nil)
{
val = null;
}
[dict setObject: val forKey: key];
}
return AUTORELEASE([dict copy]);
}
@end
@implementation NSObject (GNUstep)
/* GNU Object class compatibility */

View file

@ -290,6 +290,9 @@ NSString *GSHTTPPropertyProxyHostKey;
NSString *GSHTTPPropertyProxyPortKey;
/* Class description notification */
NSString *NSClassDescriptionNeededForClassNotification;
/*
* Setup function called when NSString is initialised.
@ -514,6 +517,10 @@ GSBuildStrings()
= [[SClass alloc] initWithCString: "GSHTTPPropertyProxyHostKey"];
GSHTTPPropertyProxyPortKey
= [[SClass alloc] initWithCString: "GSHTTPPropertyProxyPortKey"];
NSClassDescriptionNeededForClassNotification
= [[SClass alloc] initWithCString:
"NSClassDescriptionNeededForClassNotification"];
}
}