mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-27 14:00:22 +00:00
- Issue #75, Johannes Fortmann's C++ constructor and bindings patch:
With this patch, the .cxx_construct and .cxx_destruct methods will be called on NSAllocateObject/NSDeallocateObject. Note that you'll have to run gcc with -fobjc-call-cxx-cdtors to have these methods created. Additionally, there are some KVO and bindings fixes: - observing a change inside a hierarchy would give the wrong object as being changed - array operator @sum implemented - NSArrayController selectedObjects now depends on selection - some additional binding parameters implemented
This commit is contained in:
parent
e331c69257
commit
d204ace317
@ -43,7 +43,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
{
|
||||
[self setKeys:[NSArray arrayWithObjects:@"contentArray", @"selectionIndexes", nil]
|
||||
triggerChangeNotificationsForDependentKey:@"selection"];
|
||||
[self setKeys:[NSArray arrayWithObjects:@"contentArray", @"selectionIndexes", nil]
|
||||
[self setKeys:[NSArray arrayWithObjects:@"contentArray", @"selectionIndexes", @"selection", nil]
|
||||
triggerChangeNotificationsForDependentKey:@"selectedObjects"];
|
||||
[self setKeys:[NSArray arrayWithObjects:@"selectionIndexes", nil]
|
||||
triggerChangeNotificationsForDependentKey:@"canRemove"];
|
||||
@ -249,11 +249,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
#pragma mark -
|
||||
#pragma mark Moving selection
|
||||
|
||||
-(BOOL)canInsert {
|
||||
//NSUnimplementedMethod();
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)canSelectPrevious
|
||||
{
|
||||
id idxs=[[[self selectionIndexes] mutableCopy] autorelease];
|
||||
@ -389,6 +384,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
{
|
||||
id _keyPath;
|
||||
id _observer;
|
||||
id _object;
|
||||
}
|
||||
-(id)initWithKeyPath:(id)keyPath observer:(id)observer;
|
||||
-(id)observer;
|
||||
@ -436,15 +432,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
// count never changes (immutable array)
|
||||
if([keyPath isEqualToString:@"@count"])
|
||||
return;
|
||||
|
||||
|
||||
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath
|
||||
observer:observer];
|
||||
observer:observer
|
||||
object:self];
|
||||
[_observationProxies addObject:proxy];
|
||||
[proxy release];
|
||||
|
||||
NSString* firstPart, *rest;
|
||||
[keyPath _KVC_partBeforeDot:&firstPart afterDot:&rest];
|
||||
|
||||
|
||||
[_array addObserver:proxy
|
||||
toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])]
|
||||
forKeyPath:rest
|
||||
@ -470,7 +467,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
return;
|
||||
|
||||
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath
|
||||
observer:observer];
|
||||
observer:observer
|
||||
object:self];
|
||||
int idx=[_observationProxies indexOfObject:proxy];
|
||||
[proxy release];
|
||||
proxy=[_observationProxies objectAtIndex:idx];
|
||||
@ -494,12 +492,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
@end
|
||||
|
||||
@implementation _NSObservationProxy
|
||||
-(id)initWithKeyPath:(id)keyPath observer:(id)observer
|
||||
-(id)initWithKeyPath:(id)keyPath observer:(id)observer object:(id)object
|
||||
{
|
||||
if(self=[super init])
|
||||
{
|
||||
_keyPath=[keyPath retain];
|
||||
_observer=observer;
|
||||
_object=object;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -525,7 +524,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
if([other isMemberOfClass:isa])
|
||||
{
|
||||
_NSObservationProxy *o=other;
|
||||
if(o->_observer==_observer && [o->_keyPath isEqual:_keyPath])
|
||||
if(o->_observer==_observer && [o->_keyPath isEqual:_keyPath] && [o->_object isEqual:_object])
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@ -537,7 +536,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
context:(void *)context
|
||||
{
|
||||
[_observer observeValueForKeyPath:_keyPath
|
||||
ofObject:object
|
||||
ofObject:_object
|
||||
change:change
|
||||
context:context];
|
||||
}
|
||||
|
@ -22,10 +22,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
@implementation _NSBinder (BindingOptions)
|
||||
-(BOOL)conditionallySetsEditable
|
||||
{
|
||||
// FIX: needs to read from options
|
||||
if([source respondsToSelector:@selector(setEditable:)])
|
||||
return YES;
|
||||
return NO;
|
||||
return [[options objectForKey:NSConditionallySetsEditableBindingOption] boolValue];
|
||||
}
|
||||
|
||||
-(BOOL)conditionallySetsEnabled
|
||||
@ -68,6 +65,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(id)nullPlaceholder
|
||||
{
|
||||
id ret=[options objectForKey:NSNullPlaceholderBindingOption];
|
||||
if(!ret)
|
||||
return NSNoSelectionMarker;
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(id)valueTransformer
|
||||
{
|
||||
id ret=[options objectForKey:NSValueTransformerBindingOption];
|
||||
|
@ -131,16 +131,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
id newValue=[self destinationValue];
|
||||
|
||||
BOOL editable=YES;
|
||||
BOOL isPlaceholder=NO;
|
||||
if(newValue==NSMultipleValuesMarker)
|
||||
{
|
||||
newValue=[self multipleValuesPlaceholder];
|
||||
if(![self allowsEditingMultipleValues])
|
||||
editable=NO;
|
||||
isPlaceholder=YES;
|
||||
}
|
||||
else if(newValue==NSNoSelectionMarker)
|
||||
{
|
||||
newValue=[self noSelectionPlaceholder];
|
||||
editable=NO;
|
||||
isPlaceholder=YES;
|
||||
}
|
||||
else if(!newValue || newValue==[NSNull null])
|
||||
{
|
||||
newValue=[self nullPlaceholder];
|
||||
isPlaceholder=YES;
|
||||
}
|
||||
|
||||
if([self conditionallySetsEditable])
|
||||
@ -150,6 +158,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
[source setValue:newValue
|
||||
forKeyPath:bindingPath];
|
||||
|
||||
if(isPlaceholder && [source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
|
||||
[source _setCurrentValueIsPlaceholder:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"unexpected change notification for object %@ (src %@, dest %@)", object, source, destination);
|
||||
}
|
||||
|
||||
[self startObservingChanges];
|
||||
|
@ -49,6 +49,7 @@ APPKIT_EXPORT NSString* NSObservedKeyPathKey;
|
||||
APPKIT_EXPORT NSString* NSOptionsKey;
|
||||
|
||||
// Binding option keys
|
||||
APPKIT_EXPORT NSString *NSNullPlaceholderBindingOption;
|
||||
APPKIT_EXPORT NSString *NSNoSelectionPlaceholderBindingOption;
|
||||
APPKIT_EXPORT NSString *NSMultipleValuesPlaceholderBindingOption;
|
||||
APPKIT_EXPORT NSString *NSCreatesSortDescriptorBindingOption;
|
||||
@ -56,4 +57,6 @@ APPKIT_EXPORT NSString *NSRaisesForNotApplicableKeysBindingOption;
|
||||
APPKIT_EXPORT NSString *NSAllowsEditingMultipleValuesSelectionBindingOption;
|
||||
APPKIT_EXPORT NSString *NSValueTransformerNameBindingOption;
|
||||
APPKIT_EXPORT NSString *NSValueTransformerBindingOption;
|
||||
APPKIT_EXPORT NSString *NSConditionallySetsEnabledBindingOption;
|
||||
APPKIT_EXPORT NSString *NSConditionallySetsEditableBindingOption;
|
||||
|
||||
|
@ -24,13 +24,16 @@ NSString* NSObservedObjectKey=@"NSObservedObject";
|
||||
NSString* NSObservedKeyPathKey=@"NSObservedKeyPath";
|
||||
NSString* NSOptionsKey=@"NSOptions";
|
||||
|
||||
NSString *NSNullPlaceholderBindingOption=@"NSNullPlaceholder";
|
||||
NSString *NSNoSelectionPlaceholderBindingOption=@"NSNoSelectionPlaceholder";
|
||||
NSString *NSMultipleValuesPlaceholderBindingOption=@"NSMultipleValuesPlaceholder";
|
||||
NSString *NSCreatesSortDescriptorBindingOption=@"NSCreatesSortDescriptors";
|
||||
NSString *NSRaisesForNotApplicableKeysBindingOption=@"NSRaisesForNotApplicableKeys";
|
||||
NSString *NSAllowsEditingMultipleValuesSelectionBindingOption=@"NSAllowsEditingMultipleValuesSelection";
|
||||
NSString *NSValueTransformerNameBindingOption=@"NSValueTransformerName";
|
||||
NSString *NSValueTransformerBindingOption=@"NSValueTransformerBindingOption";
|
||||
NSString *NSValueTransformerBindingOption=@"NSValueTransformerBinding";
|
||||
NSString *NSConditionallySetsEnabledBindingOption=@"NSConditionallySetsEnabled";
|
||||
NSString *NSConditionallySetsEditableBindingOption=@"NSConditionallySetsEditable";
|
||||
|
||||
@implementation NSObject (BindingSupport)
|
||||
|
||||
|
@ -160,6 +160,22 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
return [self _kvo_operator_count];
|
||||
}
|
||||
|
||||
-(id)_kvo_operator_sum:(NSString*)parameter
|
||||
{
|
||||
NSArray* objects=[self valueForKeyPath:parameter];
|
||||
int count=[objects count];
|
||||
int i;
|
||||
|
||||
double sum=0.0;
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
id obj=[objects objectAtIndex:i];
|
||||
sum+=[obj doubleValue];
|
||||
}
|
||||
return [NSNumber numberWithDouble:sum];
|
||||
}
|
||||
|
||||
|
||||
-(void)setValue:(id)value forKey:(NSString*)key
|
||||
{
|
||||
id en=[self objectEnumerator];
|
||||
|
@ -323,7 +323,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
- (BOOL)validateValue:(id *)ioValue forKeyPath:(NSString *)keyPath error:(NSError **)outError
|
||||
{
|
||||
// FIX: should this be recursive or not?
|
||||
id array=[[[keyPath componentsSeparatedByString:@"."] mutableCopy] autorelease];
|
||||
id lastPathComponent=[array lastObject];
|
||||
[array removeObject:lastPathComponent];
|
||||
|
@ -16,6 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
id changeDictionary;
|
||||
int willChangeCount;
|
||||
NSString* keyPath;
|
||||
id object;
|
||||
}
|
||||
-(id)observer;
|
||||
- (id)changeDictionary;
|
||||
|
@ -116,6 +116,7 @@ static NSLock *kvoLock=nil;
|
||||
info->observer=observer;
|
||||
info->options=options;
|
||||
info->context=context;
|
||||
info->object=self;
|
||||
[info setKeyPath:keyPath];
|
||||
|
||||
// if observing a key path, also observe all deeper levels
|
||||
@ -814,7 +815,7 @@ CHANGE_DECLARATION(SEL)
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)observeValueForKeyPath:(NSString*)subKeyPath ofObject:(id)object change:(NSDictionary*)changeDict context:(void*)subContext;
|
||||
-(void)observeValueForKeyPath:(NSString*)subKeyPath ofObject:(id)subObject change:(NSDictionary*)changeDict context:(void*)subContext;
|
||||
{
|
||||
[observer observeValueForKeyPath:keyPath
|
||||
ofObject:object
|
||||
|
@ -29,3 +29,5 @@ FOUNDATION_EXPORT IMP OBJCInitializeLookupAndCacheUniqueIdForObject(id object,SE
|
||||
|
||||
FOUNDATION_EXPORT void OBJCLinkClassTable(void);
|
||||
|
||||
BOOL object_cxxConstruct(id self, Class c);
|
||||
BOOL object_cxxDestruct(id self, Class c);
|
||||
|
@ -324,6 +324,55 @@ IMP OBJCInitializeLookupAndCacheUniqueIdForObject(id object,SEL uniqueId){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline BOOL OBJCCallCXXSelector(id self, Class class, SEL selector)
|
||||
{
|
||||
struct objc_method *result=NULL;
|
||||
if(!class->super_class)
|
||||
return YES;
|
||||
|
||||
if(!OBJCCallCXXSelector(self, class->super_class, selector))
|
||||
return NO;
|
||||
|
||||
if((result=OBJCLookupUniqueIdInOnlyThisClass(class,selector))!=NULL)
|
||||
{
|
||||
if(result->method_imp(self, selector))
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
object_cxxDestruct(self, class->super_class);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL object_cxxConstruct(id self, Class class)
|
||||
{
|
||||
static SEL cxx_constructor=0;
|
||||
if(!cxx_constructor)
|
||||
cxx_constructor=sel_registerName(".cxx_construct");
|
||||
|
||||
if(!self)
|
||||
return YES;
|
||||
return OBJCCallCXXSelector(self, class, cxx_constructor);
|
||||
}
|
||||
|
||||
BOOL object_cxxDestruct(id self, Class class)
|
||||
{
|
||||
return;
|
||||
static SEL cxx_destructor=0;
|
||||
if(!cxx_destructor)
|
||||
cxx_destructor=sel_registerName(".cxx_destruct");
|
||||
|
||||
if(!self)
|
||||
return YES;
|
||||
return OBJCCallCXXSelector(self, class, cxx_destructor);
|
||||
}
|
||||
|
||||
|
||||
void OBJCLogMsg(id object,SEL message){
|
||||
#if 1
|
||||
if(object==nil)
|
||||
|
@ -62,11 +62,19 @@ id NSAllocateObject(Class class,unsigned extraBytes,NSZone *zone) {
|
||||
|
||||
result=calloc(1,class->instance_size+extraBytes);
|
||||
result->isa=class;
|
||||
|
||||
if(!object_cxxConstruct(result, object->isa))
|
||||
{
|
||||
free(result);
|
||||
result=nil;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NSDeallocateObject(id object) {
|
||||
object_cxxDestruct(object, object->isa);
|
||||
|
||||
if(NSZombieEnabled)
|
||||
NSRegisterZombie(object);
|
||||
else
|
||||
|
@ -92,11 +92,19 @@ id NSAllocateObject(Class class,unsigned extraBytes,NSZone *zone) {
|
||||
result->isa=class;
|
||||
|
||||
//OBJCLog("allocated instance of %s at %d",class->name,result);
|
||||
|
||||
|
||||
if(!object_cxxConstruct(result, result->isa))
|
||||
{
|
||||
HeapFree(zone,0,result);
|
||||
result=nil;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NSDeallocateObject(id object) {
|
||||
object_cxxDestruct(object, object->isa);
|
||||
|
||||
if(NSZombieEnabled)
|
||||
NSRegisterZombie(object);
|
||||
else {
|
||||
|
Loading…
Reference in New Issue
Block a user