2 // AIPreferenceContainer.m
5 // Created by Evan Schoenberg on 1/8/08.
8 #import "AIPreferenceContainer.h"
9 #import "AIPreferenceController.h"
10 #import <Adium/AIListObject.h>
11 #import <Adium/AILoginControllerProtocol.h>
12 #import <AIUtilities/AIDictionaryAdditions.h>
13 #import <AIUtilities/AIStringAdditions.h>
15 @interface AIPreferenceContainer (PRIVATE)
16 - (id)initForGroup:(NSString *)inGroup object:(AIListObject *)inObject;
21 #define EMPTY_CACHE_DELAY 30.0
23 @implementation AIPreferenceContainer
25 + (AIPreferenceContainer *)preferenceContainerForGroup:(NSString *)inGroup object:(AIListObject *)inObject
27 return [[[self alloc] initForGroup:inGroup object:inObject] autorelease];
30 - (id)initForGroup:(NSString *)inGroup object:(AIListObject *)inObject
32 if ((self = [super init])) {
33 group = [inGroup retain];
34 object = [inObject retain];
42 [defaults release]; defaults = nil;
51 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey
59 * @brief Empty our cache
63 [prefs release]; prefs = nil;
64 [prefsWithDefaults release]; prefsWithDefaults = nil;
68 * @brief Queue clearing of the cache
70 * If this method isn't called again within 30 seconds, the passed key will be removed from the passed cache dictionary.
72 - (void)queueClearingOfCache
74 //Cache only for 30 seconds, then release the memory
75 [NSObject cancelPreviousPerformRequestsWithTarget:self
76 selector:@selector(emptyCache)
78 [self performSelector:@selector(emptyCache)
80 afterDelay:EMPTY_CACHE_DELAY];
85 - (NSDictionary *)defaults
91 * @brief Register defaults
93 * These defaults will be added to any existing defaults; if there is overlap between keys, the new key-value pair will be used.
95 - (void)registerDefaults:(NSDictionary *)inDefaults
97 if (!defaults) defaults = [[NSMutableDictionary alloc] init];
99 [defaults addEntriesFromDictionary:inDefaults];
101 //Clear the cached defaults dictionary so it will be recreated as needed
102 [prefsWithDefaults release]; prefsWithDefaults = nil;
105 #pragma mark Get and set
108 * @brief Return a dictionary of our preferences, loading it from disk as needed
110 - (NSMutableDictionary *)prefs
113 NSString *userDirectory = [[adium loginController] userDirectory];
116 prefs = [[NSMutableDictionary dictionaryAtPath:[userDirectory stringByAppendingPathComponent:[object pathToPreferences]]
117 withName:[[object internalObjectID] safeFilenameString]
120 prefs = [[NSMutableDictionary dictionaryAtPath:userDirectory
125 [self queueClearingOfCache];
132 * @brief Return a dictionary of preferences and defaults, appropriately merged together
134 - (NSDictionary *)dictionary
136 if (!prefsWithDefaults) {
137 //Add our own preferences to the defaults dictionary to get a dict with the set keys overriding the default keys
139 prefsWithDefaults = [defaults mutableCopy];
140 [prefsWithDefaults addEntriesFromDictionary:[self prefs]];
143 prefsWithDefaults = [[self prefs] retain];
146 [self queueClearingOfCache];
149 return prefsWithDefaults;
153 * @brief Set value for key
155 * This sets and saves a preference for the given key
157 - (void)setValue:(id)value forKey:(NSString *)key
159 [self willChangeValueForKey:key];
160 //Clear the cached defaults dictionary so it will be recreated as needed
161 [prefsWithDefaults autorelease];
162 prefsWithDefaults = nil;
164 [[self prefs] setValue:value forKey:key];
165 [self didChangeValueForKey:key];
167 //Now tell the preference controller
168 if (!preferenceChangeDelays) {
169 [[adium preferenceController] informObserversOfChangedKey:key inGroup:group object:object];
174 - (id)valueForKey:(NSString *)key
176 return [[self dictionary] valueForKey:key];
180 * @brief Get a preference, possibly ignoring the defaults
183 * @param ignoreDefaults If YES, the preferences are accessed diretly, without including the default values
185 - (id)valueForKey:(NSString *)key ignoringDefaults:(BOOL)ignoreDefaults
188 return [[self prefs] valueForKey:key];
190 return [self valueForKey:key];
193 - (id)defaultValueForKey:(NSString *)key
195 return [[self defaults] valueForKey:key];
199 * @brief Set all preferences for this group
201 * All existing preferences are removed for this group; the passed dictionary becomes the new preferences
203 - (void)setPreferences:(NSDictionary *)inPreferences
205 NSEnumerator *enumerator;
206 NSArray *oldKeys = [[self prefs] allKeys];
209 [self setPreferenceChangedNotificationsEnabled:NO];
211 //Will change all old keys
212 enumerator = [oldKeys objectEnumerator];
213 while ((key = [enumerator nextObject])) {
214 [self willChangeValueForKey:@"key"];
217 [self setValuesForKeysWithDictionary:inPreferences];
219 //Did change all old keys
220 enumerator = [oldKeys objectEnumerator];
221 while ((key = [enumerator nextObject])) {
222 [self didChangeValueForKey:@"key"];
225 [self setPreferenceChangedNotificationsEnabled:YES];
228 - (void)setPreferenceChangedNotificationsEnabled:(BOOL)inEnabled
231 preferenceChangeDelays--;
233 preferenceChangeDelays++;
235 if (preferenceChangeDelays == 0) {
236 [[adium preferenceController] informObserversOfChangedKey:nil inGroup:group object:object];
243 * @brief Save to disk
247 //Save the preference change immediately (Probably not the best idea?)
248 NSString *userDirectory = [[adium loginController] userDirectory];
250 NSString *path = (object ? [userDirectory stringByAppendingPathComponent:[object pathToPreferences]] : userDirectory);
251 NSString *name = (object ? [[object internalObjectID] safeFilenameString] : group);
253 [[self prefs] writeToPath:path withName:name];
256 - (void)setGroup:(NSString *)inGroup
258 if (group != inGroup) {
260 group = [inGroup retain];
265 - (NSString *)description
267 return [NSString stringWithFormat:@"<%@ %p: Group %@, object %@>", NSStringFromClass([self class]), self, group, object];