API  0.9.10
CPUserDefaultsController.j
Go to the documentation of this file.
1 /*
2  * CPUserDefaultsController.j
3  * AppKit
4  *
5  * Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
6  * Copyright (c) 2006-2007 Christopher J. W. Lloyd
7  *
8  * Created by Alexander Ljungberg.
9  * Copyright 2011, WireLoad Inc.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25 
26 
27 
29 
30 
32 
33 @implementation CPUserDefaultsController : CPController
34 {
35  CPUserDefaults _defaults;
36  CPDictionary _initialValues;
37  BOOL _appliesImmediately;
38  id _valueProxy;
39 }
40 
42 {
45 
47 }
48 
49 - (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
50 {
51  if (self = [super init])
52  {
53  if (!someDefaults)
54  someDefaults = [CPUserDefaults standardUserDefaults];
55 
56  _defaults = someDefaults;
57  _initialValues = [initialValues copy];
58  _appliesImmediately = YES;
59  _valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
60  }
61 
62  return self;
63 }
64 
65 - (id)values
66 {
67  return _valueProxy;
68 }
69 
71 {
72  return [_valueProxy hasUnappliedChanges];
73 }
74 
75 - (void)save:(id)sender
76 {
77  [_valueProxy save];
78 }
79 
80 - (void)revert:(id)sender
81 {
82  [_valueProxy revert];
83 }
84 
85 - (void)revertToInitialValues:(id)sender
86 {
87  [_valueProxy revertToInitialValues];
88 }
89 
90 @end
91 
92 
93 var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
94 
96 
97 - (id)initWithCoder:(CPCoder)aCoder
98 {
99  if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
101 
102  self = [super initWithCoder:aCoder];
103 
104  if (self)
105  {
106  [CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
107  }
108 
109  return self;
110 }
111 
112 - (void)encodeWithCoder:(CPCoder)aCoder
113 {
114  [super encodeWithCoder:aCoder];
115 
116  if (self === SharedUserDefaultsController)
117  {
118  [aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
119  return;
120  }
121 
122  [CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
123 }
124 
125 @end
126 
127 
128 @implementation _CPUserDefaultsControllerProxy : CPObject
129 {
130  CPUserDefaultsController _controller;
131  // TODO Could be optimised with a JS dict.
132  CPMutableDictionary _cachedValues;
133 }
134 
135 - (id)initWithController:(CPUserDefaultsController)aController
136 {
137  if (self = [super init])
138  {
139  _controller = aController;
140  _cachedValues = [CPMutableDictionary dictionary];
141 
142  [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
143  }
144 
145  return self;
146 }
147 
148 - (void)dealloc
149 {
150  // FIXME No dealloc in Cappuccino.
152  [super dealloc];
153 }
154 
155 - (id)valueForKey:(CPString)aKey
156 {
157  var value = [_cachedValues objectForKey:aKey];
158  if (value === nil)
159  {
160  value = [[_controller defaults] objectForKey:aKey];
161  if (value === nil)
162  value = [[_controller initialValues] objectForKey:aKey];
163 
164  if (value !== nil)
165  [_cachedValues setObject:value forKey:aKey];
166  }
167  return value;
168 }
169 
170 - (void)setValue:(id)aValue forKey:(CPString)aKey
171 {
172  [self willChangeValueForKey:aKey];
173  [_cachedValues setObject:aValue forKey:aKey];
174  if ([_controller appliesImmediately])
175  [[_controller defaults] setObject:aValue forKey:aKey];
176  [self didChangeValueForKey:aKey];
177 }
178 
179 
180 - (void)revert
181 {
182  var keys = [_cachedValues allKeys],
183  keysCount = [keys count];
184 
185  while (keysCount--)
186  {
187  var key = keys[keysCount];
188  [self willChangeValueForKey:key];
189  [_cachedValues removeObjectForKey:key];
190  [self didChangeValueForKey:key];
191  }
192 }
193 
194 - (void)save
195 {
196  var keys = [_cachedValues allKeys],
197  keysCount = [keys count];
198 
199  while (keysCount--)
200  {
201  var key = keys[keysCount];
202  [[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
203  }
204 }
205 
206 - (void)revertToInitialValues
207 {
208  var initial = [_controller initialValues],
209  keys = [_cachedValues allKeys],
210  keysCount = [keys count];
211 
212  while (keysCount--)
213  {
214  var key = keys[keysCount];
215  [self willChangeValueForKey:key];
216 
217  var initialValue = [initial objectForKey:key];
218  if (initialValue !== nil)
219  [_cachedValues setObject:initialValue forKey:key];
220  else
221  [_cachedValues removeObjectForKey:key];
222 
223  [self didChangeValueForKey:key];
224 
225  }
226 }
227 
228 - (void)userDefaultsDidChange:(CPNotification)aNotification
229 {
230  var defaults = [_controller defaults],
231  keys = [_cachedValues allKeys],
232  keysCount = [keys count];
233 
234  while (keysCount--)
235  {
236  var key = keys[keysCount],
237  value = [_cachedValues objectForKey:key],
238  newValue = [defaults objectForKey:key];
239 
240  if (![value isEqual:newValue])
241  {
242  [self willChangeValueForKey:key];
243  [_cachedValues setObject:newValue forKey:key];
244  [self didChangeValueForKey:key];
245  }
246  }
247 }
248 
249 - (BOOL)hasUnappliedChanges
250 {
251  var defaults = [_controller defaults],
252  keys = [_cachedValues allKeys],
253  keysCount = [keys count];
254 
255  while (keysCount--)
256  {
257  var key = keys[keysCount],
258  value = [_cachedValues objectForKey:key],
259  newValue = [defaults objectForKey:key];
260 
261  if (![value isEqual:newValue])
262  return YES;
263  }
264 
265  return NO;
266 }
267 
268 @end
269 
270 
272 
277 {
278  return _defaults;
279 }
280 
284 - (CPDictionary)initialValues
285 {
286  return _initialValues;
287 }
288 
292 - (void)setInitialValues:(CPDictionary)aValue
293 {
294  _initialValues = aValue;
295 }
296 
301 {
302  return _appliesImmediately;
303 }
304 
308 - (void)setAppliesImmediately:(BOOL)aValue
309 {
310  _appliesImmediately = aValue;
311 }
312 
313 @end
Used to implement exception handling (creating & raising).
Definition: CPException.h:2
void encodeWithCoder:(CPCoder aCoder)
Definition: CPController.j:36
void willChangeValueForKey:(CPString aKey)
var isEqual
void removeObserver:(id anObserver)
void addObserver:selector:name:object:(id anObserver, [selector] SEL aSelector, [name] CPString aNotificationName, [object] id anObject)
void raise:reason:(CPString aName, [reason] CPString aReason)
Definition: CPException.j:66
id initWithDefaults:initialValues:(CPUserDefaults someDefaults, [initialValues] CPDictionary initialValues)
CPNotificationCenter defaultCenter()
A mutable key-value pair collection.
Definition: CPDictionary.h:2
id initWithCoder:(CPCoder aDecoder)
Definition: CPController.j:42
An immutable string (collection of characters).
Definition: CPString.h:2
CPUserDefaultsDidChangeNotification
var CPUserDefaultsControllerSharedKey
A notification that can be posted to a CPNotificationCenter.
Definition: CPNotification.h:2
void didChangeValueForKey:(CPString aKey)
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
void dealloc()
Definition: CPObject.j:171
Sends messages (CPNotification) between objects.
global CPUserDefaultsDidChangeNotification var SharedUserDefaultsController
CPDictionary copy()
Definition: CPDictionary.j:292
id alloc()
Definition: CPObject.j:130