Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Source / AIPreferenceContainer.m
blob0e105aae266392491d5b67aea9a9a418d6924e92
1 //
2 //  AIPreferenceContainer.m
3 //  Adium
4 //
5 //  Created by Evan Schoenberg on 1/8/08.
6 //
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;
17 - (void)emptyCache;
18 - (void)save;
19 @end
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];
35         }
36         
37         return self;
40 - (void)dealloc
42         [defaults release]; defaults = nil;
43         [group release];
44         [object release];
46         [self emptyCache];
47         
48         [super dealloc];
51 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey
53         return NO;
56 #pragma mark Cache
58 /*!
59  * @brief Empty our cache
60  */
61 - (void)emptyCache
63         [prefs release]; prefs = nil;
64         [prefsWithDefaults release]; prefsWithDefaults = nil;
67 /*!
68  * @brief Queue clearing of the cache
69  *
70  * If this method isn't called again within 30 seconds, the passed key will be removed from the passed cache dictionary.
71  */
72 - (void)queueClearingOfCache
74         //Cache only for 30 seconds, then release the memory
75         [NSObject cancelPreviousPerformRequestsWithTarget:self
76                                                                                          selector:@selector(emptyCache)
77                                                                                            object:nil];
78         [self performSelector:@selector(emptyCache)
79                            withObject:nil
80                            afterDelay:EMPTY_CACHE_DELAY];
83 #pragma mark Defaults
85 - (NSDictionary *)defaults
87         return defaults;
90 /*!
91  * @brief Register defaults
92  *
93  * These defaults will be added to any existing defaults; if there is overlap between keys, the new key-value pair will be used.
94  */
95 - (void)registerDefaults:(NSDictionary *)inDefaults
97         if (!defaults) defaults = [[NSMutableDictionary alloc] init];
98         
99         [defaults addEntriesFromDictionary:inDefaults];
100         
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
109  */
110 - (NSMutableDictionary *)prefs
112         if (!prefs) {
113                 NSString        *userDirectory = [[adium loginController] userDirectory];
114                 
115                 if (object) {
116                         prefs = [[NSMutableDictionary dictionaryAtPath:[userDirectory stringByAppendingPathComponent:[object pathToPreferences]]
117                                                                                                   withName:[[object internalObjectID] safeFilenameString]
118                                                                                                         create:YES] retain];
119                 } else {
120                         prefs = [[NSMutableDictionary dictionaryAtPath:userDirectory
121                                                                                                   withName:group
122                                                                                                         create:YES] retain];
123                 }
124                 
125                 [self queueClearingOfCache];
126         }
127         
128         return prefs;
132  * @brief Return a dictionary of preferences and defaults, appropriately merged together
133  */
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
138                 if (defaults) {
139                         prefsWithDefaults = [defaults mutableCopy];
140                         [prefsWithDefaults addEntriesFromDictionary:[self prefs]];
142                 } else {
143                         prefsWithDefaults = [[self prefs] retain];
144                 }
145                 
146                 [self queueClearingOfCache];
147         }
149         return prefsWithDefaults;
153  * @brief Set value for key
155  * This sets and saves a preference for the given key
156  */
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];
170                 [self save];
171         }
174 - (id)valueForKey:(NSString *)key
176         return [[self dictionary] valueForKey:key];
180  * @brief Get a preference, possibly ignoring the defaults
182  * @param key The key
183  * @param ignoreDefaults If YES, the preferences are accessed diretly, without including the default values
184  */
185 - (id)valueForKey:(NSString *)key ignoringDefaults:(BOOL)ignoreDefaults
187         if (ignoreDefaults)
188                 return [[self prefs] valueForKey:key];
189         else
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
202  */
203 - (void)setPreferences:(NSDictionary *)inPreferences
205         NSEnumerator *enumerator;
206         NSArray          *oldKeys = [[self prefs] allKeys];
207         NSString         *key;
208         
209         [self setPreferenceChangedNotificationsEnabled:NO];
211         //Will change all old keys
212         enumerator = [oldKeys objectEnumerator];        
213         while ((key = [enumerator nextObject])) {
214                 [self willChangeValueForKey:@"key"];
215         }
216         
217         [self setValuesForKeysWithDictionary:inPreferences];
218         
219         //Did change all old keys
220         enumerator = [oldKeys objectEnumerator];        
221         while ((key = [enumerator nextObject])) {
222                 [self didChangeValueForKey:@"key"];
223         }
224         
225         [self setPreferenceChangedNotificationsEnabled:YES];
228 - (void)setPreferenceChangedNotificationsEnabled:(BOOL)inEnabled
230         if (inEnabled) 
231                 preferenceChangeDelays--;
232         else
233                 preferenceChangeDelays++;
234         
235         if (preferenceChangeDelays == 0) {
236                 [[adium preferenceController] informObserversOfChangedKey:nil inGroup:group object:object];
237                 [self save];
238         }
241 #pragma mark Saving
243  * @brief Save to disk
244  */
245 - (void)save
247         //Save the preference change immediately (Probably not the best idea?)
248         NSString        *userDirectory = [[adium loginController] userDirectory];
249         
250         NSString        *path = (object ? [userDirectory stringByAppendingPathComponent:[object pathToPreferences]] : userDirectory);
251         NSString        *name = (object ? [[object internalObjectID] safeFilenameString] : group);
252         
253         [[self prefs] writeToPath:path withName:name];
256 - (void)setGroup:(NSString *)inGroup
258         if (group != inGroup) {
259                 [group release];
260                 group = [inGroup retain];
261         }
264 #pragma mark Debug
265 - (NSString *)description
267         return [NSString stringWithFormat:@"<%@ %p: Group %@, object %@>", NSStringFromClass([self class]), self, group, object];
269 @end