added missing file

some fixes for selection proxy observing
This commit is contained in:
Johannes Fortmann 2008-09-16 15:19:59 +00:00
parent d6a3cf8b5c
commit 16a61e1d2f
6 changed files with 259 additions and 39 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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];
}

View File

@ -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"];
}

View 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

View 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