mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2025-02-18 18:49:32 +00:00
added missing file
some fixes for selection proxy observing
This commit is contained in:
parent
d6a3cf8b5c
commit
16a61e1d2f
@ -19,7 +19,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
@interface NSObjectController(private)
|
||||
-(id)_defaultNewObject;
|
||||
-(void)_selectionMayHaveChanged;
|
||||
-(void)_selectionWillChange;
|
||||
-(void)_selectionDidChange;
|
||||
@end
|
||||
|
||||
@interface NSArrayController(forwardRefs)
|
||||
@ -87,7 +88,8 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
[self _selectionMayHaveChanged];
|
||||
[self _selectionWillChange];
|
||||
[self _selectionDidChange];
|
||||
}
|
||||
|
||||
- (BOOL)preservesSelection
|
||||
@ -119,8 +121,6 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
|
||||
{
|
||||
[self setSelectionIndexes:oldSelectionIndexes];
|
||||
}
|
||||
|
||||
[self _selectionMayHaveChanged];
|
||||
}
|
||||
|
||||
- (id)contentArray {
|
||||
@ -211,11 +211,12 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
|
||||
// use isEqualToIndexSet: ?
|
||||
if (_selectionIndexes != value) {
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
|
||||
[self _selectionWillChange];
|
||||
|
||||
[_selectionIndexes release];
|
||||
_selectionIndexes = [value copy];
|
||||
[self _selectionMayHaveChanged];
|
||||
|
||||
[self _selectionDidChange];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
return YES;
|
||||
}
|
||||
|
@ -13,10 +13,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
@interface NSControllerSelectionProxy : NSObject
|
||||
{
|
||||
id controller;
|
||||
NSMutableDictionary *values;
|
||||
id _controller;
|
||||
NSMutableDictionary *_values;
|
||||
NSMutableArray *_observationProxies;
|
||||
id _keys;
|
||||
}
|
||||
-(id)initWithController:(id)cont;
|
||||
-(void)notifyControllerChange;
|
||||
-(void)controllerWillChange;
|
||||
|
||||
-(void)controllerDidChange;
|
||||
@end
|
||||
|
@ -22,8 +22,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
{
|
||||
if((self=[super init]))
|
||||
{
|
||||
values=[NSMutableDictionary new];
|
||||
controller = [cont retain];
|
||||
_values=[NSMutableDictionary new];
|
||||
_controller = [cont retain];
|
||||
_observationProxies = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
@ -31,8 +31,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
[values release];
|
||||
[controller release];
|
||||
[_keys release];
|
||||
[_values release];
|
||||
[_controller release];
|
||||
|
||||
if([_observationProxies count]>0)
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
@ -46,10 +47,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
-(id)valueForKey:(NSString*)key
|
||||
{
|
||||
id val=[values objectForKey:key];
|
||||
id val=[_values objectForKey:key];
|
||||
if(val)
|
||||
return val;
|
||||
id allValues=[[controller selectedObjects] valueForKeyPath:key];
|
||||
id allValues=[[_controller selectedObjects] valueForKeyPath:key];
|
||||
|
||||
switch([allValues count])
|
||||
{
|
||||
@ -61,7 +62,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if([controller alwaysUsesMultipleValuesMarker])
|
||||
if([_controller alwaysUsesMultipleValuesMarker])
|
||||
{
|
||||
val=NSMultipleValuesMarker;
|
||||
}
|
||||
@ -80,24 +81,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
}
|
||||
}
|
||||
|
||||
[values setValue:val forKey:key];
|
||||
[_values setValue:val forKey:key];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
-(int)count
|
||||
{
|
||||
return [values count];
|
||||
return [_values count];
|
||||
}
|
||||
|
||||
-(id)keyEnumerator
|
||||
{
|
||||
return [values keyEnumerator];
|
||||
return [_values keyEnumerator];
|
||||
}
|
||||
|
||||
-(void)setValue:(id)value forKey:(NSString *)key
|
||||
{
|
||||
[[controller selectedObjects] setValue:value forKey:key];
|
||||
[[_controller selectedObjects] setValue:value forKey:key];
|
||||
}
|
||||
|
||||
-(NSString*)description
|
||||
@ -108,18 +109,26 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
self];
|
||||
}
|
||||
|
||||
-(void)notifyControllerChange
|
||||
-(void)controllerWillChange
|
||||
{
|
||||
id keys=[values allKeys];
|
||||
for(id key in keys)
|
||||
[_keys autorelease];
|
||||
_keys=[[_values allKeys] retain];
|
||||
for(id key in _keys)
|
||||
{
|
||||
[self willChangeValueForKey:key];
|
||||
}
|
||||
[values removeAllObjects];
|
||||
for(id key in keys)
|
||||
[_values removeAllObjects];
|
||||
}
|
||||
|
||||
-(void)controllerDidChange
|
||||
{
|
||||
[_values removeAllObjects];
|
||||
for(id key in _keys)
|
||||
{
|
||||
[self didChangeValueForKey:key];
|
||||
}
|
||||
[_keys autorelease];
|
||||
_keys=nil;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
@ -127,7 +136,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context
|
||||
{
|
||||
[values removeObjectForKey:keyPath];
|
||||
[_values removeObjectForKey:keyPath];
|
||||
}
|
||||
|
||||
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
|
||||
@ -135,7 +144,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath observer:observer object:self];
|
||||
[_observationProxies addObject:proxy];
|
||||
|
||||
[[controller selectedObjects] addObserver:proxy forKeyPath:keyPath options:options context:context];
|
||||
[[_controller selectedObjects] addObserver:proxy forKeyPath:keyPath options:options context:context];
|
||||
|
||||
[proxy release];
|
||||
}
|
||||
@ -146,7 +155,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
int idx=[_observationProxies indexOfObject:proxy];
|
||||
[proxy release];
|
||||
|
||||
[[controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:idx] forKeyPath:keyPath];
|
||||
[[_controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:idx] forKeyPath:keyPath];
|
||||
|
||||
[_observationProxies removeObjectAtIndex:idx];
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
#import "NSObservationProxy.h"
|
||||
|
||||
@interface NSObjectController(forward)
|
||||
-(void)_selectionMayHaveChanged;
|
||||
-(void)_selectionWillChange;
|
||||
-(void)_selectionDidChange;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObjectController
|
||||
@ -44,9 +46,12 @@ triggerChangeNotificationsForDependentKey:@"canRemove"];
|
||||
|
||||
- (void)setContent:(id)value {
|
||||
if (_content != value) {
|
||||
[self _selectionWillChange];
|
||||
|
||||
[_content release];
|
||||
_content = [value retain];
|
||||
[self _selectionMayHaveChanged];
|
||||
|
||||
[self _selectionDidChange];
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,16 +75,19 @@ triggerChangeNotificationsForDependentKey:@"canRemove"];
|
||||
return [self _defaultNewObject];
|
||||
}
|
||||
|
||||
|
||||
-(void)_selectionMayHaveChanged
|
||||
-(void)_selectionWillChange
|
||||
{
|
||||
[self willChangeValueForKey:@"selection"];
|
||||
if(_selection)
|
||||
{
|
||||
[_selection notifyControllerChange];
|
||||
}
|
||||
else
|
||||
[self willChangeValueForKey:@"selection"];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)_selectionDidChange
|
||||
{
|
||||
if(!_selection)
|
||||
_selection=[[NSControllerSelectionProxy alloc] initWithController:self];
|
||||
[_selection controllerDidChange];
|
||||
[self didChangeValueForKey:@"selection"];
|
||||
}
|
||||
|
||||
|
26
AppKit/NSController/NSObservationProxy.h
Normal file
26
AppKit/NSController/NSObservationProxy.h
Normal file
@ -0,0 +1,26 @@
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSMutableArray.h>
|
||||
|
||||
@interface _NSObservationProxy : NSObject
|
||||
{
|
||||
id _keyPath;
|
||||
id _observer;
|
||||
id _object;
|
||||
BOOL _notifyObject;
|
||||
}
|
||||
-(id)initWithKeyPath:(id)keyPath observer:(id)observer object:(id)object;
|
||||
-(id)observer;
|
||||
-(id)keyPath;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface _NSObservableArray : NSArray
|
||||
{
|
||||
NSArray *_array;
|
||||
NSMutableArray *_observationProxies;
|
||||
}
|
||||
-initWithObjects:(id *)objects count:(unsigned)count;
|
||||
@end
|
||||
|
173
AppKit/NSController/NSObservationProxy.m
Normal file
173
AppKit/NSController/NSObservationProxy.m
Normal file
@ -0,0 +1,173 @@
|
||||
#import "NSObservationProxy.h"
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSString+KVCAdditions.h>
|
||||
#import <Foundation/NSKeyValueObserving.h>
|
||||
|
||||
@implementation _NSObservationProxy
|
||||
-(id)initWithKeyPath:(id)keyPath observer:(id)observer object:(id)object
|
||||
{
|
||||
if((self=[super init]))
|
||||
{
|
||||
_keyPath=[keyPath retain];
|
||||
_observer=observer;
|
||||
_object=object;
|
||||
if([object respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)])
|
||||
_notifyObject=YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
[_keyPath release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(id)observer
|
||||
{
|
||||
return _observer;
|
||||
}
|
||||
|
||||
-(id)keyPath
|
||||
{
|
||||
return _keyPath;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)other
|
||||
{
|
||||
if([other isMemberOfClass:isa])
|
||||
{
|
||||
_NSObservationProxy *o=other;
|
||||
if(o->_observer==_observer && [o->_keyPath isEqual:_keyPath] && [o->_object isEqual:_object])
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context
|
||||
{
|
||||
if(_notifyObject)
|
||||
[_object observeValueForKeyPath:_keyPath
|
||||
ofObject:_object
|
||||
change:change
|
||||
context:context];
|
||||
|
||||
[_observer observeValueForKeyPath:_keyPath
|
||||
ofObject:_object
|
||||
change:change
|
||||
context:context];
|
||||
}
|
||||
|
||||
-(NSString*)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation _NSObservableArray
|
||||
|
||||
-(id)objectAtIndex:(unsigned)idx
|
||||
{
|
||||
return [_array objectAtIndex:idx];
|
||||
}
|
||||
|
||||
-(unsigned)count
|
||||
{
|
||||
return [_array count];
|
||||
}
|
||||
|
||||
-initWithObjects:(id *)objects count:(unsigned)count;
|
||||
{
|
||||
if((self=[super init]))
|
||||
{
|
||||
_array=[[NSArray alloc] initWithObjects:objects count:count];
|
||||
_observationProxies=[NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
if([_observationProxies count]>0)
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"_NSObservableArray still being observed by %@ on %@",
|
||||
[[_observationProxies objectAtIndex:0] observer],
|
||||
[[_observationProxies objectAtIndex:0] keyPath]];
|
||||
[_observationProxies release];
|
||||
[_array release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)addObserver:(id)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context;
|
||||
{
|
||||
if([keyPath hasPrefix:@"@"])
|
||||
{
|
||||
// count never changes (immutable array)
|
||||
if([keyPath isEqualToString:@"@count"])
|
||||
return;
|
||||
|
||||
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath
|
||||
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
|
||||
options:options
|
||||
context:context];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_array addObserver:observer
|
||||
toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])]
|
||||
forKeyPath:keyPath
|
||||
options:options
|
||||
context:context];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)removeObserver:(id)observer forKeyPath:(NSString*)keyPath;
|
||||
{
|
||||
if([keyPath hasPrefix:@"@"])
|
||||
{
|
||||
// count never changes (immutable array)
|
||||
if([keyPath isEqualToString:@"@count"])
|
||||
return;
|
||||
|
||||
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath
|
||||
observer:observer
|
||||
object:self];
|
||||
int idx=[_observationProxies indexOfObject:proxy];
|
||||
[proxy release];
|
||||
proxy=[_observationProxies objectAtIndex:idx];
|
||||
|
||||
NSString* firstPart, *rest;
|
||||
[keyPath _KVC_partBeforeDot:&firstPart afterDot:&rest];
|
||||
|
||||
[_array removeObserver:proxy
|
||||
fromObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])]
|
||||
forKeyPath:rest];
|
||||
|
||||
[_observationProxies removeObjectAtIndex:idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_array removeObserver:observer
|
||||
fromObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])]
|
||||
forKeyPath:keyPath];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user