assorted controller behavior fixes

This commit is contained in:
Christopher Lloyd 2010-03-10 16:33:22 +00:00
parent 3c0f029d38
commit 418c3a5bd9
7 changed files with 146 additions and 205 deletions

View File

@ -9,7 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#import <AppKit/NSObjectController.h> #import <AppKit/NSObjectController.h>
@class NSPredicate,NSIndexSet; @class NSPredicate,NSIndexSet,NSMutableIndexSet;
@interface NSArrayController : NSObjectController { @interface NSArrayController : NSObjectController {
struct struct
@ -21,7 +21,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
long selectsInsertedObjects:1; long selectsInsertedObjects:1;
long alwaysUsesMultipleValuesMarker:1; long alwaysUsesMultipleValuesMarker:1;
} _flags; } _flags;
id _selectionIndexes; NSMutableIndexSet *_selectionIndexes;
id _sortDescriptors; id _sortDescriptors;
id _filterPredicate; id _filterPredicate;
id _arrangedObjects; id _arrangedObjects;

View File

@ -112,9 +112,9 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
-(void)setContent:(id)value -(void)setContent:(id)value
{ {
if(![value isKindOfClass:[NSArray class]]) if(value!=nil && ![value isKindOfClass:[NSArray class]])
value=[NSArray arrayWithObject:value]; value=[NSArray arrayWithObject:value];
id oldSelection=nil; id oldSelection=nil;
id oldSelectionIndexes=[[[self selectionIndexes] copy] autorelease]; id oldSelectionIndexes=[[[self selectionIndexes] copy] autorelease];
if([self preservesSelection]) if([self preservesSelection])
@ -147,16 +147,19 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
} }
- (id)contentArray { - (id)contentArray {
return [self content]; id result=[self content];
return result;
} }
-(NSArray*)arrangeObjects:(NSArray*)objects -(NSArray*)arrangeObjects:(NSArray*)objects {
{
id sortedObjects=objects; id sortedObjects=objects;
if([self filterPredicate]) if([self filterPredicate])
sortedObjects=[sortedObjects filteredArrayUsingPredicate:[self filterPredicate]]; sortedObjects=[sortedObjects filteredArrayUsingPredicate:[self filterPredicate]];
if([self sortDescriptors]) if([self sortDescriptors])
sortedObjects=[sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]]; sortedObjects=[sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]];
return sortedObjects; return sortedObjects;
} }
@ -166,15 +169,11 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
} }
- (void)_setArrangedObjects:(id)value { - (void)_setArrangedObjects:(id)value {
if (_arrangedObjects != value) [_arrangedObjects autorelease];
{ _arrangedObjects = [[_NSObservableArray alloc] initWithArray:value];
[_arrangedObjects release];
_arrangedObjects = [[_NSObservableArray alloc] initWithArray:value];
}
} }
-(id)arrangedObjects -arrangedObjects {
{
return _arrangedObjects; return _arrangedObjects;
} }
@ -221,23 +220,24 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
} }
- (NSIndexSet *)selectionIndexes { - (NSIndexSet *)selectionIndexes {
return [[_selectionIndexes retain] autorelease]; return _selectionIndexes;
} }
- (BOOL)setSelectionIndexes:(NSIndexSet *)value { - (BOOL)setSelectionIndexes:(NSIndexSet *)value {
if(![value count] && _flags.avoidsEmptySelection && [[self arrangedObjects] count])
value=[NSIndexSet indexSetWithIndex:0]; if(_flags.avoidsEmptySelection && [value count]==0 && [[self arrangedObjects] count])
value=[NSIndexSet indexSetWithIndex:0];
value=[[value mutableCopy] autorelease]; NSMutableIndexSet *mutableValue=[[value mutableCopy] autorelease];
[(NSMutableIndexSet *)value removeIndexesInRange:NSMakeRange([[self arrangedObjects] count]+1, NSNotFound)];
[mutableValue removeIndexesInRange:NSMakeRange([[self arrangedObjects] count]+1, NSNotFound)];
// use isEqualToIndexSet: ? if (![_selectionIndexes isEqualToIndexSet: mutableValue]) {
if (_selectionIndexes != value) {
[self willChangeValueForKey:@"selectionIndexes"]; [self willChangeValueForKey:@"selectionIndexes"];
[self _selectionWillChange]; [self _selectionWillChange];
[_selectionIndexes release]; [_selectionIndexes release];
_selectionIndexes = [value copy]; _selectionIndexes = [mutableValue retain];
[self _selectionDidChange]; [self _selectionDidChange];
[self didChangeValueForKey:@"selectionIndexes"]; [self didChangeValueForKey:@"selectionIndexes"];
@ -319,9 +319,6 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
} }
} }
#pragma mark -
#pragma mark NSSet support
-(id)_contentSet -(id)_contentSet
{ {
return [NSSet setWithArray:_content]; return [NSSet setWithArray:_content];
@ -332,13 +329,8 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
[self setContent:[set allObjects]]; [self setContent:[set allObjects]];
} }
#pragma mark - - (void)addObject:(id)object {
#pragma mark Add/Remove // Don't check canAdd here as this can be used programmatically to add objects
- (void)addObject:(id)object
{
if(![self canAdd])
return;
[self willChangeValueForKey:@"content"]; [self willChangeValueForKey:@"content"];
[_content addObject:object]; [_content addObject:object];
@ -347,39 +339,44 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
if(_flags.clearsFilterPredicateOnInsertion) if(_flags.clearsFilterPredicateOnInsertion)
[self setFilterPredicate:nil]; [self setFilterPredicate:nil];
if([_filterPredicate evaluateWithObject:object]) if([self filterPredicate]==nil || [_filterPredicate evaluateWithObject:object]){
{ // FIXME: this should probably use arrangeObjects: to get subclass behavior
[self willChangeValueForKey:@"selectionIndexes"]; [self willChangeValueForKey:@"arrangedObjects"];
NSUInteger pos=[_arrangedObjects _insertObject:object inArraySortedByDescriptors:_sortDescriptors]; NSUInteger pos=[_arrangedObjects _insertObject:object inArraySortedByDescriptors:_sortDescriptors];
[self didChangeValueForKey:@"arrangedObjects"];
[self willChangeValueForKey:@"selectionIndexes"];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
[self didChangeValueForKey:@"selectionIndexes"]; [self didChangeValueForKey:@"selectionIndexes"];
} }
} }
- (void)removeObject:(id)object -(void)removeObject:(id)object {
{ // Don't check canremove/editable here as this can be used programmatically to remove objects
if(![self canRemove])
return;
[self willChangeValueForKey:@"content"]; [self willChangeValueForKey:@"content"];
[_content removeObject:object]; [_content removeObject:object];
[self didChangeValueForKey:@"content"]; [self didChangeValueForKey:@"content"];
if([_filterPredicate evaluateWithObject:object]) if([self filterPredicate]==nil || [_filterPredicate evaluateWithObject:object]){
{ // FIXME: this should probably use arrangeObjects: to get subclass behavior
[self willChangeValueForKey:@"arrangedObjects"];
NSUInteger pos=[_arrangedObjects indexOfObject:object]; NSUInteger pos=[_arrangedObjects indexOfObject:object];
[self willChangeValueForKey:@"selectionIndexes"];
[_arrangedObjects removeObject:object]; [_arrangedObjects removeObject:object];
[self didChangeValueForKey:@"arrangedObjects"];
[self willChangeValueForKey:@"selectionIndexes"];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1]; [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
[self didChangeValueForKey:@"selectionIndexes"]; [self didChangeValueForKey:@"selectionIndexes"];
} }
} }
-(void)add:(id)sender -(void)add:(id)sender {
{
if(![self canAdd]) if(![self canAdd])
return; return;
[self insert:sender]; [self insert:sender];
} }
@ -387,6 +384,7 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
{ {
if(![self canInsert]) if(![self canInsert])
return; return;
id toAdd=nil; id toAdd=nil;
if([self automaticallyPreparesContent]) if([self automaticallyPreparesContent])
toAdd=[[self newObject] autorelease]; toAdd=[[self newObject] autorelease];
@ -395,22 +393,21 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
[self addObject:toAdd]; [self addObject:toAdd];
} }
-(void)remove:(id)sender -(void)remove:(id)sender {
{ if(![self canRemove])
return;
[self removeObjects:[[self contentArray] objectsAtIndexes:[self selectionIndexes]]]; [self removeObjects:[[self contentArray] objectsAtIndexes:[self selectionIndexes]]];
} }
-(void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet*)indexes -(void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet*)indexes {
{ [self removeObjects:[[self contentArray] objectsAtIndexes:indexes]];
// FIXME: this should remove no matter what canRemove returns
[self removeObjects:[[self contentArray] objectsAtIndexes:indexes]];
} }
- (void)addObjects:(NSArray *)objects - (void)addObjects:(NSArray *)objects {
{ // Don't check canAdd/editable here as this can be used programmatically to add objects
if(![self canAdd])
return;
id contentArray=[[[self contentArray] mutableCopy] autorelease]; id contentArray=[[[self contentArray] mutableCopy] autorelease];
int count=[objects count]; int count=[objects count];
int i; int i;
@ -420,10 +417,8 @@ triggerChangeNotificationsForDependentKey:@"selectionIndex"];
} }
- (void)removeObjects:(NSArray *)objects - (void)removeObjects:(NSArray *)objects {
{ // Don't check canRemove here as this can be used programmatically to remove objects
if(![self canRemove])
return;
id contentArray=[[[self contentArray] mutableCopy] autorelease]; id contentArray=[[[self contentArray] mutableCopy] autorelease];
int count=[objects count]; int count=[objects count];

View File

@ -164,7 +164,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath observer:observer object:self]; _NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath observer:observer object:self];
int idx=[_observationProxies indexOfObject:proxy]; int idx=[_observationProxies indexOfObject:proxy];
if(idx==NSNotFound) { if(idx==NSNotFound) {
NSLog(@"%@ not found in %@", proxy, _observationProxies);
} }
[proxy release]; [proxy release];

View File

@ -20,30 +20,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
@end @end
@implementation NSObjectController @implementation NSObjectController
+(void)initialize +(void)initialize {
{ [self setKeys:[NSArray arrayWithObjects:@"editable", nil] triggerChangeNotificationsForDependentKey:@"canAdd"];
[self setKeys:[NSArray arrayWithObjects:@"editable", nil] [self setKeys:[NSArray arrayWithObjects:@"editable", nil] triggerChangeNotificationsForDependentKey:@"canInsert"];
triggerChangeNotificationsForDependentKey:@"canAdd"]; [self setKeys:[NSArray arrayWithObjects:@"editable", @"selection", nil] triggerChangeNotificationsForDependentKey:@"canRemove"];
[self setKeys:[NSArray arrayWithObjects:@"editable", nil] [self setKeys:[NSArray arrayWithObjects:@"content", nil] triggerChangeNotificationsForDependentKey:@"contentObject"];
triggerChangeNotificationsForDependentKey:@"canInsert"];
[self setKeys:[NSArray arrayWithObjects:@"editable", @"selection", nil]
triggerChangeNotificationsForDependentKey:@"canRemove"];
[self setKeys:[NSArray arrayWithObjects:@"content", nil]
triggerChangeNotificationsForDependentKey:@"contentObject"];
} }
-(id)initWithCoder:(NSCoder*)coder -initWithCoder:(NSCoder*)coder {
{ if((self=[super init])) {
if((self=[super init]))
{ _objectClassName=[[coder decodeObjectForKey:@"NSObjectClassName"] copy];
_objectClassName=[[coder decodeObjectForKey:@"NSObjectClassName"] retain]; if(_objectClassName==nil)
_editable = [coder decodeBoolForKey:@"NSEditable"]; _objectClassName=@"NSMutableDictionary";
_automaticallyPreparesContent = [coder decodeBoolForKey:@"NSAutomaticallyPreparesContent"];
_observedKeys=[[NSCountedSet alloc] init]; _editable = [coder decodeBoolForKey:@"NSEditable"];
_selection=[[NSControllerSelectionProxy alloc] initWithController:self]; _automaticallyPreparesContent = [coder decodeBoolForKey:@"NSAutomaticallyPreparesContent"];
}
return self; _observedKeys=[[NSCountedSet alloc] init];
_selection=[[NSControllerSelectionProxy alloc] initWithController:self];
}
return self;
} }
- (id)content { - (id)content {
@ -73,7 +70,8 @@ triggerChangeNotificationsForDependentKey:@"contentObject"];
-(NSArray *)selectedObjects -(NSArray *)selectedObjects
{ {
return [NSArray arrayWithObject:_content]; NSArray *result=[NSArray arrayWithObject:_content];
return result;
} }
-(id)selection -(id)selection

View File

@ -15,7 +15,7 @@
void* _context; void* _context;
NSKeyValueObservingOptions _options; NSKeyValueObservingOptions _options;
} }
-(id)initWithKeyPath:(id)keyPath observer:(id)observer object:(id)object; -initWithKeyPath:(NSString *)keyPath observer:(id)observer object:(id)object;
-(id)observer; -(id)observer;
-(id)keyPath; -(id)keyPath;
-(void)setNotifyObject:(BOOL)val; -(void)setNotifyObject:(BOOL)val;

View File

@ -1,46 +1,58 @@
/* Copyright (c) 2007 Johannes Fortmann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import "NSObservationProxy.h" #import "NSObservationProxy.h"
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSException.h> #import <Foundation/NSException.h>
#import "NSStringKVCFunctions.h"
#import <Foundation/NSKeyValueObserving.h> #import <Foundation/NSKeyValueObserving.h>
#import <Foundation/NSIndexSet.h> #import <Foundation/NSIndexSet.h>
@implementation _NSObservationProxy void NSStringKVCSplitOnDot(NSString *self,NSString **before,NSString **after){
-(id)initWithKeyPath:(id)keyPath observer:(id)observer object:(id)object NSRange range=[self rangeOfString:@"."];
{ if(range.location!=NSNotFound)
if((self=[super init]))
{ {
_keyPath=[keyPath retain]; *before=[self substringToIndex:range.location];
_observer=observer; *after=[self substringFromIndex:range.location+1];
_object=object;
} }
else
{
*before=self;
*after=nil;
}
}
@implementation _NSObservationProxy
-initWithKeyPath:(NSString *)keyPath observer:(id)observer object:(id)object {
_keyPath=[keyPath retain];
_observer=observer;
_object=object;
return self; return self;
} }
-(void)dealloc -(void)dealloc {
{ [_keyPath release];
[_keyPath release]; [super dealloc];
[super dealloc];
} }
-(id)observer -observer {
{
return _observer; return _observer;
} }
-(id)keyPath -keyPath {
{ return _keyPath;
return _keyPath;
} }
-(void*)context -(void *)context {
{
return _context; return _context;
} }
-(NSKeyValueObservingOptions)options -(NSKeyValueObservingOptions)options {
{
return _options; return _options;
} }
@ -60,76 +72,54 @@
return NO; return NO;
} }
- (void)observeValueForKeyPath:(NSString *)keyPath - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
ofObject:(id)object if(_notifyObject) {
change:(NSDictionary *)change [_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:_context];
context:(void *)context
{
if(_notifyObject)
{
[_object observeValueForKeyPath:_keyPath
ofObject:_object
change:change
context:_context];
} }
[_observer observeValueForKeyPath:_keyPath [_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:_context];
ofObject:_object
change:change
context:_context];
} }
-(NSString*)description -(NSString *)description {
{
return [NSString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath]; return [NSString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
} }
@end @end
@implementation _NSObservableArray @implementation _NSObservableArray
-(id)objectAtIndex:(NSUInteger)idx -objectAtIndex:(NSUInteger)idx {
{ return [_array objectAtIndex:idx];
return [_array objectAtIndex:idx];
} }
-(NSUInteger)count -(NSUInteger)count {
{
return [_array count]; return [_array count];
} }
-(id)init { -init {
return [self initWithObjects:NULL count:0]; return [self initWithObjects:NULL count:0];
} }
-initWithObjects:(id *)objects count:(NSUInteger)count; -initWithObjects:(id *)objects count:(NSUInteger)count {
{ _array=[[NSMutableArray alloc] initWithObjects:objects count:count];
if((self=[super init])) _observationProxies=[NSMutableArray new];
{
_array=[[NSMutableArray alloc] initWithObjects:objects count:count];
_observationProxies=[NSMutableArray new];
}
return self; return self;
} }
-(void)dealloc -(void)dealloc {
{ if([_observationProxies count]>0)
if([_observationProxies count]>0) [NSException raise:NSInvalidArgumentException format:@"_NSObservableArray still being observed by %@ on %@",
[NSException raise:NSInvalidArgumentException [[_observationProxies objectAtIndex:0] observer],[[_observationProxies objectAtIndex:0] keyPath]];
format:@"_NSObservableArray still being observed by %@ on %@",
[[_observationProxies objectAtIndex:0] observer], [_observationProxies release];
[[_observationProxies objectAtIndex:0] keyPath]]; [_array release];
[_observationProxies release];
[_array release];
[_roi release]; [_roi release];
[super dealloc]; [super dealloc];
} }
-(void)addObserver:(id)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context; -(void)addObserver:(id)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context {
{
// init the proxy // init the proxy
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath _NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath observer:observer object:self];
observer:observer
object:self];
proxy->_options=options; proxy->_options=options;
proxy->_context=context; proxy->_context=context;
[_observationProxies addObject:proxy]; [_observationProxies addObject:proxy];
@ -149,10 +139,7 @@
NSStringKVCSplitOnDot(keyPath,&firstPart,&rest); NSStringKVCSplitOnDot(keyPath,&firstPart,&rest);
// observe ourselves // observe ourselves
[super addObserver:observer [super addObserver:observer forKeyPath:keyPath options:options context:context];
forKeyPath:keyPath
options:options
context:context];
// if there's anything the operator depends on, observe _all_ objects for that path // if there's anything the operator depends on, observe _all_ objects for that path
keyPath=rest; keyPath=rest;
@ -161,20 +148,13 @@
// add observer proxy for all relevant indexes // add observer proxy for all relevant indexes
if([_array count] && keyPath) { if([_array count] && keyPath) {
[_array addObserver:proxy [_array addObserver:proxy toObjectsAtIndexes:idxs forKeyPath:keyPath options:options context:context];
toObjectsAtIndexes:idxs
forKeyPath:keyPath
options:options
context:context];
} }
} }
-(void)removeObserver:(id)observer forKeyPath:(NSString*)keyPath; -(void)removeObserver:(id)observer forKeyPath:(NSString*)keyPath {
{
// find the proxy again // find the proxy again
_NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath _NSObservationProxy *proxy=[[_NSObservationProxy alloc] initWithKeyPath:keyPath observer:observer object:self];
observer:observer
object:self];
int idx=[_observationProxies indexOfObject:proxy]; int idx=[_observationProxies indexOfObject:proxy];
[proxy release]; [proxy release];
proxy=[[[_observationProxies objectAtIndex:idx] retain] autorelease]; proxy=[[[_observationProxies objectAtIndex:idx] retain] autorelease];
@ -194,17 +174,14 @@
NSString* firstPart, *rest; NSString* firstPart, *rest;
NSStringKVCSplitOnDot(keyPath,&firstPart,&rest); NSStringKVCSplitOnDot(keyPath,&firstPart,&rest);
[super removeObserver:observer [super removeObserver:observer forKeyPath:keyPath];
forKeyPath:keyPath];
// remove dependent key path from all children // remove dependent key path from all children
keyPath=rest; keyPath=rest;
idxs=[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])]; idxs=[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [_array count])];
} }
if([_array count] && keyPath) { if([_array count] && keyPath) {
[_array removeObserver:proxy [_array removeObserver:proxy fromObjectsAtIndexes:idxs forKeyPath:keyPath];
fromObjectsAtIndexes:idxs
forKeyPath:keyPath];
} }
} }
@ -263,14 +240,13 @@
NSString* firstPart, *rest; NSString* firstPart, *rest;
NSStringKVCSplitOnDot(keyPath,&firstPart,&rest); NSStringKVCSplitOnDot(keyPath,&firstPart,&rest);
if(rest) if(rest) {
[obj removeObserver:proxy [obj removeObserver:proxy forKeyPath:rest];
forKeyPath:rest]; }
} }
else { else {
if(!_roi || [_roi containsIndex:idx]) { if(!_roi || [_roi containsIndex:idx]) {
[obj removeObserver:proxy [obj removeObserver:proxy forKeyPath:keyPath];
forKeyPath:keyPath];
} }
} }
} }
@ -288,13 +264,11 @@
} }
} }
-(void)addObject:(id)obj -(void)addObject:(id)obj {
{
[self insertObject:obj atIndex:[self count]]; [self insertObject:obj atIndex:[self count]];
} }
-(void)removeLastObject -(void)removeLastObject {
{
[self removeObjectAtIndex:[self count]-1]; [self removeObjectAtIndex:[self count]-1];
} }
@ -311,8 +285,7 @@
NSStringKVCSplitOnDot(keyPath,&firstPart,&rest); NSStringKVCSplitOnDot(keyPath,&firstPart,&rest);
if(rest) { if(rest) {
[old removeObserver:proxy [old removeObserver:proxy forKeyPath:[proxy keyPath]];
forKeyPath:[proxy keyPath]];
[obj addObserver:proxy [obj addObserver:proxy
forKeyPath:rest forKeyPath:rest
@ -322,8 +295,7 @@
} }
else { else {
if(!_roi || [_roi containsIndex:idx]) { if(!_roi || [_roi containsIndex:idx]) {
[old removeObserver:proxy [old removeObserver:proxy forKeyPath:[proxy keyPath]];
forKeyPath:[proxy keyPath]];
[obj addObserver:proxy [obj addObserver:proxy
forKeyPath:[proxy keyPath] forKeyPath:[proxy keyPath]

View File

@ -1,23 +0,0 @@
/* Copyright (c) 2007 Johannes Fortmann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import <Foundation/NSString.h>
void NSStringKVCSplitOnDot(NSString *self,NSString **before,NSString **after){
NSRange range=[self rangeOfString:@"."];
if(range.location!=NSNotFound)
{
*before=[self substringToIndex:range.location];
*after=[self substringFromIndex:range.location+1];
}
else
{
*before=self;
*after=nil;
}
}