diff --git a/ChangeLog b/ChangeLog index 3ea1ae309..a1adc3ddd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-01-05 Fred Kiefer + + * Headers/AppKit/NSController.h, + * Source/NSController.m: Add one 10.4 method. + * Headers/AppKit/NSUserDefaultsController.h: Add one 10.4 method. + * Source/NSUserDefaultsController.m: Fully implement class. + 2009-01-05 Richard Frith-Macdonald * Source/NSScroller.m: Fixup/reorganisation of setting names for diff --git a/Headers/AppKit/NSController.h b/Headers/AppKit/NSController.h index 80fa383b1..288b07500 100644 --- a/Headers/AppKit/NSController.h +++ b/Headers/AppKit/NSController.h @@ -30,7 +30,7 @@ #include -#if OS_API_VERSION(100300,GS_API_LATEST) +#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST) @class NSMutableArray; @@ -50,6 +50,12 @@ - (void) objectDidBeginEditing: (id)editor; - (void) objectDidEndEditing: (id)editor; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) +- (void) commitEditingWithDelegate: (id)delegate + didCommitSelector: (SEL)didCommitSelector + contextInfo: (void*)contextInfo; +#endif + @end #endif // OS_API_VERSION diff --git a/Headers/AppKit/NSUserDefaultsController.h b/Headers/AppKit/NSUserDefaultsController.h index 162c9a046..2a0520a06 100644 --- a/Headers/AppKit/NSUserDefaultsController.h +++ b/Headers/AppKit/NSUserDefaultsController.h @@ -31,7 +31,7 @@ #include -#if OS_API_VERSION(100300,GS_API_LATEST) +#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST) @class NSUserDefaults; @class NSDictionary; @@ -41,6 +41,7 @@ { NSUserDefaults* _defaults; NSDictionary* _initial_values; + id _values; BOOL _applies_immediately; } @@ -58,6 +59,9 @@ - (void) revert: (id)sender; - (void) revertToInitialValues: (id)sender; - (void) save: (id)sender; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST) +- (BOOL) hasUnappliedChanges; +#endif @end diff --git a/Source/NSController.m b/Source/NSController.m index 6ad025fff..7f527c94e 100644 --- a/Source/NSController.m +++ b/Source/NSController.m @@ -68,13 +68,13 @@ if((self = [super init]) != nil) { if([aDecoder allowsKeyedCoding]) - { - ASSIGN(_declared_keys,[aDecoder decodeObjectForKey: @"NSDeclaredKeys"]); - } + { + ASSIGN(_declared_keys,[aDecoder decodeObjectForKey: @"NSDeclaredKeys"]); + } else - { - ASSIGN(_declared_keys,[aDecoder decodeObject]); - } + { + ASSIGN(_declared_keys,[aDecoder decodeObject]); + } } return self; } @@ -93,13 +93,34 @@ { if (![[_editors objectAtIndex: i] commitEditing]) { - return NO; - } + return NO; + } } return YES; } +- (void) commitEditingWithDelegate: (id)delegate + didCommitSelector: (SEL)didCommitSelector + contextInfo: (void*)contextInfo +{ + unsigned c = [_editors count]; + unsigned i; + + for (i = 0; i < c; i++) + { + BOOL didCommit = [[_editors objectAtIndex: i] commitEditing]; + if (delegate != nil && didCommitSelector != NULL) + { + void (*meth)(id, SEL, id, BOOL, void*); + meth = (void (*)(id, SEL, id, BOOL, void*))[delegate methodForSelector: + didCommitSelector]; + if (meth) + meth(delegate, didCommitSelector, self, didCommit, contextInfo); + } + } +} + - (void) discardEditing { [_editors makeObjectsPerformSelector: @selector(discardEditing)]; diff --git a/Source/NSUserDefaultsController.m b/Source/NSUserDefaultsController.m index a4e358350..8f98a4525 100644 --- a/Source/NSUserDefaultsController.m +++ b/Source/NSUserDefaultsController.m @@ -26,21 +26,149 @@ Boston, MA 02110-1301, USA. */ +#include #include +#include +#include +#include #include #include static id shared = nil; +@interface GSUserDefaultsHelper : NSObject +{ +@public + NSUserDefaultsController *controller; + NSMutableDictionary *values; +} + +- (id) initWithController: (NSUserDefaultsController*)udc; +- (id) valueForKey: (NSString*)key; +- (void) setValue: (id)value forKey: (NSString*)key; + +- (void) revert; +- (void) revertToInitialValues: (NSDictionary *)initial; +- (void) defaultsDidChange: (NSUserDefaults *)defaults; +@end + +@implementation GSUserDefaultsHelper + +- (id) initWithController: (NSUserDefaultsController*)udc +{ + if ((self = [super init]) != nil) + { + // We are retained by the controller + controller = udc; + values = [[NSMutableDictionary alloc] init]; + } + + return self; +} + +- (void) dealloc +{ + RELEASE(values); + [super dealloc]; +} + +- (id) valueForKey: (NSString*)key +{ + id value = [values objectForKey: key]; + + if (!value) + { + // If the value isn't cached, get it from the controller and cache it. + value = [[controller defaults] objectForKey: key]; + if (!value) + { + value = [[controller initialValues] objectForKey: key]; + } + // We need to cache the values we return to be able to + // report changes to them when the defaults change. + if (value) + [values setObject: value forKey: key]; + } + NSLog(@"returning %@ for key %@", value, key); + + return value; +} + +- (void) setValue: (id)value forKey: (NSString*)key +{ + [self willChangeValueForKey: key]; + [values setObject: value forKey: key]; + if ([controller appliesImmediately]) + [[controller defaults] setObject: value forKey: key]; + [self didChangeValueForKey: key]; +} + +- (void) revert +{ + NSEnumerator *e; + NSString *key; + + e = [values keyEnumerator]; + while ((key = (NSString *)[e nextObject])) + { + [self willChangeValueForKey: key]; + [values removeObjectForKey: key]; + [self didChangeValueForKey: key]; + } +} + +- (void) revertToInitialValues: (NSDictionary *)initial +{ + NSEnumerator *e; + NSString *key; + + e = [values keyEnumerator]; + while ((key = (NSString *)[e nextObject])) + { + id val = [values objectForKey: key]; + id oldVal = [initial objectForKey: key]; + + if (oldVal && ![val isEqual: oldVal]) + { + [self willChangeValueForKey: key]; + [values setObject: oldVal forKey: key]; + // When appliesImmediately is YES, should we save these values? + [self didChangeValueForKey: key]; + } + } +} + +- (void) defaultsDidChange: (NSUserDefaults *)defaults +{ + NSEnumerator *e; + NSString *key; + + e = [values keyEnumerator]; + while ((key = (NSString *)[e nextObject])) + { + id val = [values objectForKey: key]; + id newVal = [defaults objectForKey: key]; + + if (newVal && ![val isEqual: newVal]) + { + [self willChangeValueForKey: key]; + [values setObject: newVal forKey: key]; + [self didChangeValueForKey: key]; + } + } +} + +@end + @implementation NSUserDefaultsController + (id) sharedUserDefaultsController { if (shared == nil) { - shared = [[NSUserDefaultsController alloc] - initWithDefaults: nil - initialValues: nil]; + shared = [[NSUserDefaultsController alloc] + initWithDefaults: nil + initialValues: nil]; } return shared; } @@ -51,17 +179,35 @@ static id shared = nil; if ((self = [super init]) != nil) { if (defaults == nil) - { - defaults = [NSUserDefaults standardUserDefaults]; - } - + { + defaults = [NSUserDefaults standardUserDefaults]; + } + ASSIGN(_defaults, defaults); + [self setAppliesImmediately: YES]; [self setInitialValues: initialValues]; + _values = [[GSUserDefaultsHelper alloc] + initWithController: self]; + // Watch for user default change notifications + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(defaultsDidChange:) + name: NSUserDefaultsDidChangeNotification + object: _defaults]; } return self; } +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + RELEASE(_values); + RELEASE(_defaults); + RELEASE(_initial_values); + [super dealloc]; +} + - (NSUserDefaults*) defaults { return _defaults; @@ -69,8 +215,7 @@ static id shared = nil; - (id) values { - // TODO - return nil; + return _values; } - (NSDictionary*) initialValues @@ -80,7 +225,7 @@ static id shared = nil; - (void) setInitialValues: (NSDictionary*)values { - ASSIGN(_initial_values, values); + ASSIGNCOPY(_initial_values, values); } - (BOOL) appliesImmediately @@ -98,18 +243,79 @@ static id shared = nil; [self discardEditing]; if (![self appliesImmediately]) { - // TODO + [_values revert]; } } - (void) revertToInitialValues: (id)sender { - // TODO + [self discardEditing]; + [_values revertToInitialValues: _initial_values]; } - (void) save: (id)sender { - // TODO + if (![self appliesImmediately]) + { + NSDictionary *values = ((GSUserDefaultsHelper*)_values)->values; + NSEnumerator *e; + NSString *key; + + e = [values keyEnumerator]; + while ((key = (NSString *)[e nextObject])) + { + [_defaults setObject: [values objectForKey: key] forKey: key]; + } + } +} + +- (BOOL) hasUnappliedChanges +{ + NSDictionary *values = ((GSUserDefaultsHelper*)_values)->values; + NSEnumerator *e; + NSString *key; + + e = [values keyEnumerator]; + while ((key = (NSString *)[e nextObject])) + { + id val = [values objectForKey: key]; + id newVal = [_defaults objectForKey: key]; + + if (![val isEqual: newVal]) + { + return YES; + } + } + return NO; +} + +- (void) defaultsDidChange: (NSNotification*)notification +{ + [_values defaultsDidChange: _defaults]; +} + +- (void) encodeWithCoder: (NSCoder *)aCoder +{ + if ([aCoder allowsKeyedCoding]) + if (self == [NSUserDefaultsController sharedUserDefaultsController]) + { + [aCoder encodeBool: YES forKey: @"NSSharedInstance"]; + return; + } + + [super encodeWithCoder: aCoder]; +} + +- (id) initWithCoder: (NSCoder *)aDecoder +{ + if ([aDecoder allowsKeyedCoding]) + if ([aDecoder decodeBoolForKey: @"NSSharedInstance"]) + { + RELEASE(self); + return [NSUserDefaultsController sharedUserDefaultsController]; + } + + return [super initWithCoder: aDecoder]; } @end